diff --git a/Cargo.lock b/Cargo.lock index ba43a2d5..18d2ec1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10194,6 +10194,7 @@ dependencies = [ "reth-cli-commands", "reth-cli-util", "reth-db", + "reth-db-common", "reth-discv4", "reth-engine-local", "reth-engine-primitives", diff --git a/Cargo.toml b/Cargo.toml index 3b57e22c..54a0bc43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,18 @@ path = "src/lib.rs" name = "reth-bsc" path = "src/main.rs" +[[bin]] +name = "miner-bench" +path = "src/bench_main.rs" +required-features = ["bench-test"] + [dependencies] reth = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-cli = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-cli-commands = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-basic-payload-builder = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-db = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } +reth-db-common = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-engine-local = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-engine-tree = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } reth-node-builder = { git = "https://github.com/bnb-chain/reth.git", branch = "develop" } diff --git a/src/bench/README.md b/src/bench/README.md new file mode 100644 index 00000000..28926004 --- /dev/null +++ b/src/bench/README.md @@ -0,0 +1,88 @@ +# Miner Benchmark + +This directory contains the `miner-bench` CLI, which is a local benchmark harness for +measuring block building, state-root computation, and post-build persistence costs. + +## What It Measures + +The main supported command on this branch is `run`, which executes a direct block-building +microbenchmark: + +- initializes a temporary MDBX database from genesis +- optionally enables trieDB before genesis +- builds a setup block that deploys and distributes an ERC20 token +- executes a configurable number of benchmark blocks with synthetic ERC20 transfers +- finalizes the block +- persists block/state changes and reports timing breakdowns + +The reported persistence bucket is real local work. It includes: + +- block insert +- state write +- triedb flush +- database commit + +## Supported Commands + +### `run` + +This is the supported benchmark mode on this branch. + +Example: + +```bash +cargo run --features bench-test --bin miner-bench -- run \ + --num-blocks 3 \ + --txs-per-block 500 \ + --funded-accounts 500 \ + --background-accounts 1000000 \ + --storage-slots-per-account 10 \ + --triedb \ + --output benchmark.csv +``` + +### `payload-job-run` + +This command is currently unavailable on this branch. The upstream refactor removed the +`BscPayloadJob` / wait-slice scheduling APIs that the original payload-job benchmark depended on. +The command remains reserved so the CLI shape is explicit, but it returns an error if invoked. + +## trieDB Flag + +The benchmark CLI uses `--triedb`. + +That is the benchmark-side equivalent of running the node with: + +```bash +reth-bsc node --statedb.triedb +``` + +When `--triedb` is enabled, the benchmark initializes the global triedb manager before genesis so +the builder/finalization flow runs against triedb-backed state logic on this branch. + +## Branch-Specific Caveats + +- `--chain-difflayers` is ignored by the direct benchmark on this branch. + The current builder API does not expose difflayer-returning finalize hooks here. +- The direct benchmark is still a microbenchmark, not a full node simulation. +- Transactions are pre-recovered during pool generation so the measured execution loop reflects + block-building work more closely than signer recovery overhead. +- The workload is synthetic ERC20 traffic, not a live heterogeneous mempool. + +## Interpreting Results + +Useful high-level buckets: + +- `tx_execution_us`: aggregate transaction execution time +- `execute_only_us`: time spent inside `execute_transaction()` +- `finish_us`: post-execution finalize work, including state-root computation +- `commit_us`: aggregate persistence work +- `insert_block_us`, `write_state_us`, `triedb_flush_us`, `provider_commit_us`: + persistence subphases + +In practice on this branch: + +- `finish_us` is the relevant builder/finalize number +- `commit_us` is the relevant post-build persistence number +- the benchmark is useful for tuning builder/root/persistence behavior +- it should not be described as a full real-miner simulation diff --git a/src/bench/config.rs b/src/bench/config.rs new file mode 100644 index 00000000..89bc41db --- /dev/null +++ b/src/bench/config.rs @@ -0,0 +1,205 @@ +use alloy_primitives::B256; +use clap::{Parser, Subcommand}; +use std::path::PathBuf; + +/// Hardcoded validator private keys (from local node-deploy keystores) +const VALIDATOR_KEY_0: &str = "937f86f4a49cafcf81a2595c5e7afd08b875b42bf05a18aa5ebc64a0af584000"; +const VALIDATOR_KEY_1: &str = "ac24b6aeb63fc825b2866a5ad628c42c1c5222c56c1c9f2cedfffd95d96c75a0"; +const VALIDATOR_KEY_2: &str = "c73e6841e8e422048a8eafb0e8a2e62059b5d4fe9195b87d49e9b6c1c635549f"; + +/// Hardcoded genesis-funded deployer account private key +const DEPLOYER_KEY: &str = "59ba8068eb256d520179e903f43dacf6d8d57d72bd306e1bd603fdb8c8da10e8"; + +/// Default genesis path (local copy in testing/) +const DEFAULT_GENESIS: &str = "testing/genesis_local.json"; + +#[derive(Parser, Debug)] +#[command(name = "miner-bench", about = "BSC execution/state-root microbenchmark")] +pub struct Cli { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + /// Run the block-execution microbenchmark (direct pipeline) + Run(RunArgs), + /// Reserved payload-job benchmark command (currently unavailable on this branch) + PayloadJobRun(PayloadJobRunArgs), + /// Compare two benchmark CSV outputs + Compare(CompareArgs), +} + +#[derive(Parser, Debug)] +pub struct RunArgs { + /// Path to genesis JSON file + #[arg(long, default_value = DEFAULT_GENESIS)] + pub genesis: PathBuf, + + /// Number of blocks to mine + #[arg(long, default_value = "100")] + pub num_blocks: usize, + + /// Number of transactions per block + #[arg(long, default_value = "200")] + pub txs_per_block: usize, + + /// Number of funded accounts for tx generation + #[arg(long, default_value = "500")] + pub funded_accounts: usize, + + /// Number of extra "background" accounts to inflate the state trie (no txs, just state bulk) + #[arg(long, default_value = "0")] + pub background_accounts: usize, + + /// Number of storage slots per background account (simulates token balances, approvals, etc.) + #[arg(long, default_value = "5")] + pub storage_slots_per_account: usize, + + /// Enable difflayer chain (unsupported on this branch; ignored by the direct benchmark) + #[arg(long, default_value = "false")] + pub chain_difflayers: bool, + + /// Enable trieDB for state root calculation + #[arg(long, default_value = "false")] + pub triedb: bool, + + /// Output CSV file path + #[arg(long, default_value = "benchmark.csv")] + pub output: PathBuf, + + /// Label for this benchmark run + #[arg(long, default_value = "default")] + pub label: String, +} + +#[derive(Parser, Debug)] +pub struct PayloadJobRunArgs { + /// Path to genesis JSON file + #[arg(long, default_value = DEFAULT_GENESIS)] + pub genesis: PathBuf, + + /// Number of payload-job iterations to run + #[arg(long, default_value = "20")] + pub iterations: usize, + + /// Number of transactions to populate in the pool per iteration + #[arg(long, default_value = "200")] + pub txs_per_iteration: usize, + + /// Number of funded accounts for tx generation + #[arg(long, default_value = "500")] + pub funded_accounts: usize, + + /// Number of extra background accounts to inflate the state trie + #[arg(long, default_value = "0")] + pub background_accounts: usize, + + /// Number of storage slots per background account + #[arg(long, default_value = "5")] + pub storage_slots_per_account: usize, + + /// Enable difflayer chaining between payload-job iterations + #[arg(long, default_value = "false")] + pub chain_difflayers: bool, + + /// Enable trieDB for payload finalization + #[arg(long, default_value = "false")] + pub triedb: bool, + + // --- Wait-Slice Parameters --- + /// DELAY_LEFT_OVER: ms reserved for finalization (default: 120) + #[arg(long, default_value = "120")] + pub delay_left_over_ms: u64, + + /// TIME_MULTIPLIER: retry threshold multiplier (default: 2) + #[arg(long, default_value = "2")] + pub time_multiplier: u32, + + /// Grace period past expected_end_timestamp_ms in ms (default: 150) + #[arg(long, default_value = "150")] + pub grace_period_ms: u128, + + /// Max wait-slice duration per iteration in ms (default: 50) + #[arg(long, default_value = "50")] + pub max_wait_slice_ms: u64, + + /// Override mining delay in ms (default: use parlia computation). + /// Set to e.g. 330 to simulate a realistic BSC block period. + #[arg(long)] + pub mining_delay_ms: Option, + + /// Percentage of txs to pre-load before starting the job (0-100, default: 100). + /// Remaining txs are drip-fed mid-job to trigger retries and concurrent builds. + #[arg(long, default_value = "100")] + pub initial_tx_pct: u32, + + /// Delay in ms before starting to drip-feed remaining txs (default: 50). + #[arg(long, default_value = "50")] + pub tx_drip_delay_ms: u64, + + /// Interval in ms between drip-feed batches (default: 20). + #[arg(long, default_value = "20")] + pub tx_drip_interval_ms: u64, + + /// Output CSV file + #[arg(long, default_value = "payload_job_benchmark.csv")] + pub output: PathBuf, + + /// Label for this run + #[arg(long, default_value = "default")] + pub label: String, +} + +#[derive(Parser, Debug)] +pub struct CompareArgs { + /// Baseline CSV file + #[arg(long)] + pub baseline: PathBuf, + + /// Optimized CSV file + #[arg(long)] + pub optimized: PathBuf, +} + +pub struct BenchConfig { + pub genesis_path: PathBuf, + pub private_keys: Vec, + pub deployer_key: B256, + pub num_blocks: usize, + pub txs_per_block: usize, + pub funded_accounts: usize, + pub background_accounts: usize, + pub storage_slots_per_account: usize, + pub chain_difflayers: bool, + pub triedb: bool, + pub output_csv: PathBuf, + pub label: String, +} + +fn parse_key(hex: &str) -> B256 { + hex.parse::().expect("hardcoded key must be valid") +} + +impl BenchConfig { + pub fn from_run_args(args: RunArgs) -> eyre::Result { + Ok(Self { + genesis_path: args.genesis, + private_keys: vec![ + parse_key(VALIDATOR_KEY_0), + parse_key(VALIDATOR_KEY_1), + parse_key(VALIDATOR_KEY_2), + ], + deployer_key: parse_key(DEPLOYER_KEY), + num_blocks: args.num_blocks, + txs_per_block: args.txs_per_block, + funded_accounts: args.funded_accounts, + background_accounts: args.background_accounts, + storage_slots_per_account: args.storage_slots_per_account, + chain_difflayers: args.chain_difflayers, + triedb: args.triedb, + output_csv: args.output, + label: args.label, + }) + } +} diff --git a/src/bench/db_init.rs b/src/bench/db_init.rs new file mode 100644 index 00000000..a234dd54 --- /dev/null +++ b/src/bench/db_init.rs @@ -0,0 +1,318 @@ +use crate::bench::config::BenchConfig; +use crate::chainspec::BscChainSpec; +use crate::consensus::parlia::Parlia; +use crate::consensus::parlia::provider::{EnhancedDbSnapshotProvider, SnapshotProvider}; +use crate::consensus::parlia::snapshot::Snapshot; +use crate::hardforks::bsc::BscHardfork; +use crate::node::BscNode; +use crate::node::evm::util::insert_header_to_cache; + +use alloy_consensus::Header; +use alloy_genesis::Genesis; +use alloy_primitives::{Address, B256, Keccak256, U256}; +use reth::api::NodeTypesWithDBAdapter; +use reth_chainspec::{ + BaseFeeParams, BaseFeeParamsKind, Chain, ChainSpec, NamedChain, make_genesis_header, +}; +use reth_db::{DatabaseEnv, init_db, mdbx::DatabaseArguments}; +use reth_db_common::init::init_genesis; +use reth_primitives::SealedHeader; +use reth_provider::{ProviderFactory, providers::StaticFileProvider}; +use rust_eth_triedb::triedb_manager::init_global_triedb_manager; +use secp256k1::{PublicKey, SECP256K1, SecretKey}; +use std::collections::HashMap; +use std::sync::Arc; + +/// The concrete NodeTypes adapter for the benchmark ProviderFactory. +pub type BscNodeTypes = NodeTypesWithDBAdapter>; + +/// Result of database initialization +pub struct InitResult { + pub chain_spec: Arc, + pub genesis_header: SealedHeader, + pub genesis_snapshot: Snapshot, + pub parlia: Arc>, + pub snapshot_provider: Arc>>, + pub validator_addresses: Vec
, + pub funded_accounts: Vec<(B256, Address)>, + pub factory: ProviderFactory, + pub temp_dir: std::path::PathBuf, + pub snapshot_db: Arc, +} + +/// Derive Address from a private key B256 +pub fn address_from_private_key(key: &B256) -> Address { + let sk = SecretKey::from_slice(key.as_ref()).expect("invalid private key"); + let pk = PublicKey::from_secret_key(SECP256K1, &sk); + let uncompressed = pk.serialize_uncompressed(); + let mut hasher = Keccak256::new(); + hasher.update(&uncompressed[1..]); + let hash = hasher.finalize(); + Address::from_slice(&hash[12..]) +} + +/// Create the BscChainSpec from a user-provided genesis JSON. +pub fn create_chain_spec(genesis: Genesis) -> Arc { + let hardforks = BscHardfork::bsc_local(); + let genesis_header = make_genesis_header(&genesis, &hardforks); + let hash = genesis_header.hash_slow(); + + let inner = ChainSpec { + chain: Chain::from_named(NamedChain::BinanceSmartChain), + genesis, + paris_block_and_final_difficulty: Some((0, U256::from(0))), + hardforks, + deposit_contract: None, + base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::new(1, 1)), + prune_delete_limit: 3500, + genesis_header: SealedHeader::new(genesis_header, hash), + ..Default::default() + }; + Arc::new(BscChainSpec { inner }) +} + +/// Initialize the benchmark database and all infrastructure from genesis. +/// +/// Creates a real MDBX database with ProviderFactory, writes genesis state +/// via `init_genesis`, and returns a fully-initialized `InitResult` that +/// can serve state via `factory.latest()` / `factory.history_by_block_number()`. +/// +/// If `config.triedb` is true, trieDB is initialized BEFORE genesis so that +/// `init_genesis` writes state to the trieDB PathDB instead of the MDBX trie tables. +pub fn init_benchmark(config: &BenchConfig) -> eyre::Result { + // 1. Load genesis JSON + let genesis_data = std::fs::read_to_string(&config.genesis_path) + .map_err(|e| eyre::eyre!("Failed to read genesis file: {}", e))?; + let genesis: Genesis = serde_json::from_str(&genesis_data) + .map_err(|e| eyre::eyre!("Failed to parse genesis JSON: {}", e))?; + + // 2. Generate funded accounts early so we can inject them into genesis alloc + let funded_accounts = generate_funded_accounts(config.funded_accounts); + + // 3. Inject funded accounts into genesis alloc (so init_genesis writes them to MDBX) + let balance = U256::from(1_000_000u64) * U256::from(10u64).pow(U256::from(18)); // 1M BNB + let mut genesis = genesis; + for (_, addr) in &funded_accounts { + genesis + .alloc + .entry(*addr) + .or_insert_with(|| alloy_genesis::GenesisAccount { balance, ..Default::default() }); + } + + // 3b. Inject background accounts to inflate the state trie (simulates mainnet state size) + if config.background_accounts > 0 { + println!( + " Generating {} background accounts with {} storage slots each...", + config.background_accounts, config.storage_slots_per_account + ); + let small_balance = U256::from(1u64) * U256::from(10u64).pow(U256::from(18)); // 1 BNB + for i in 0..config.background_accounts { + let mut key_bytes = [0u8; 32]; + key_bytes[0] = 0xBB; // prefix for background accounts + let idx_bytes = (i as u64 + 1).to_be_bytes(); + key_bytes[24..32].copy_from_slice(&idx_bytes); + let addr = address_from_private_key(&B256::from(key_bytes)); + + // Add storage slots (simulates ERC20 balances, approvals, etc.) + let storage = if config.storage_slots_per_account > 0 { + let mut map = std::collections::BTreeMap::new(); + for s in 0..config.storage_slots_per_account { + let mut slot_bytes = [0u8; 32]; + slot_bytes[24..32].copy_from_slice(&(s as u64).to_be_bytes()); + let slot = B256::from(slot_bytes); + let mut val_bytes = [0u8; 32]; + val_bytes[31] = 1; // non-zero value + map.insert(slot, B256::from(val_bytes)); + } + Some(map) + } else { + None + }; + + genesis.alloc.entry(addr).or_insert_with(|| alloy_genesis::GenesisAccount { + balance: small_balance, + storage, + ..Default::default() + }); + } + println!(" Injected {} background accounts into genesis", config.background_accounts); + } + + // 4. Create chain spec (with funded accounts in alloc) + let chain_spec = create_chain_spec(genesis); + + // 5. Get validator addresses from private keys + let validator_addresses: Vec
= + config.private_keys.iter().map(address_from_private_key).collect(); + + println!("Validators:"); + for (i, addr) in validator_addresses.iter().enumerate() { + println!(" [{}] {}", i, addr); + } + + // 4. Create temp directory structure for MDBX + static files + let temp_dir = std::env::temp_dir().join(format!("miner_bench_{}", std::process::id())); + if temp_dir.exists() { + std::fs::remove_dir_all(&temp_dir)?; + } + std::fs::create_dir_all(&temp_dir)?; + + let db_path = temp_dir.join("db"); + std::fs::create_dir_all(&db_path)?; + + let static_files_path = temp_dir.join("static_files"); + std::fs::create_dir_all(&static_files_path)?; + + // Production initializes the global triedb manager before any genesis/state writes. + // The benchmark must do the same or `is_triedb_active()` stays false and no difflayers + // or prefetchers are ever produced during block finalization. + if config.triedb { + let triedb_path = temp_dir.join("rust_eth_triedb"); + std::fs::create_dir_all(&triedb_path)?; + let triedb_path_str = triedb_path.to_string_lossy(); + init_global_triedb_manager(triedb_path_str.as_ref()); + } + + // 5. Create MDBX database + let db = Arc::new( + init_db(&db_path, DatabaseArguments::new(Default::default())) + .map_err(|e| eyre::eyre!("Failed to create main database: {}", e))?, + ); + + // 6. Create StaticFileProvider + let static_file_provider = StaticFileProvider::read_write(&static_files_path) + .map_err(|e| eyre::eyre!("Failed to create static file provider: {}", e))?; + + // 7. Create ProviderFactory + let rocksdb_provider = reth_provider::providers::RocksDBProvider::new(temp_dir.join("rocksdb")) + .map_err(|e| eyre::eyre!("Failed to create RocksDB provider: {}", e))?; + let factory = ProviderFactory::::new( + db.clone(), + chain_spec.clone(), + static_file_provider, + rocksdb_provider, + ) + .map_err(|e| eyre::eyre!("Failed to create ProviderFactory: {}", e))?; + + // 8. Write genesis state to the database + // When trieDB is active, this writes state to trieDB PathDB instead of MDBX trie tables + let genesis_hash = + init_genesis(&factory).map_err(|e| eyre::eyre!("Failed to initialize genesis: {}", e))?; + + println!("Genesis initialized in MDBX, hash: {}", genesis_hash); + + // 9. Create snapshot MDBX database (for Parlia consensus snapshots) + let snap_db_path = temp_dir.join("snap_db"); + std::fs::create_dir_all(&snap_db_path)?; + let snapshot_db = Arc::new( + init_db(&snap_db_path, DatabaseArguments::new(Default::default())) + .map_err(|e| eyre::eyre!("Failed to create snapshot database: {}", e))?, + ); + + // 10. Create Parlia consensus + let parlia = Arc::new(Parlia::new(chain_spec.clone(), 200)); + + // 11. Get the genesis header from chain spec + let genesis_header_ref = chain_spec.inner.genesis_header(); + let genesis_sealed_hash = genesis_header_ref.hash_slow(); + let genesis_sealed = SealedHeader::new(genesis_header_ref.clone(), genesis_sealed_hash); + + // 12. Insert genesis header into the header cache + insert_header_to_cache(genesis_header_ref.clone()); + + // 13. Create genesis snapshot from header validators + let genesis_snapshot = + create_genesis_snapshot(&parlia, genesis_header_ref, &validator_addresses); + + // 14. Create snapshot provider and insert genesis snapshot + let snapshot_provider = + Arc::new(EnhancedDbSnapshotProvider::new(snapshot_db.clone(), 2048, chain_spec.clone())); + snapshot_provider.insert(genesis_snapshot.clone()); + + // 15. Register snapshot provider globally (needed by BscBlockExecutor::prepare_new_block) + let _ = crate::shared::set_snapshot_provider( + snapshot_provider.clone() as Arc + ); + + println!( + "Database initialized: {} funded accounts, genesis hash: {}", + funded_accounts.len(), + genesis_hash + ); + + Ok(InitResult { + chain_spec, + genesis_header: genesis_sealed, + genesis_snapshot, + parlia, + snapshot_provider, + validator_addresses, + funded_accounts, + factory, + temp_dir, + snapshot_db, + }) +} + +/// Create a genesis snapshot for the validator set. +fn create_genesis_snapshot( + parlia: &Parlia, + genesis_header: &Header, + validators: &[Address], +) -> Snapshot { + // Try to parse validators from the genesis header extra_data first + let epoch_length = parlia.epoch; + let parsed = parlia.parse_validators_from_header(genesis_header, epoch_length); + + let (addrs, vote_addrs) = match parsed { + Ok(info) => { + let vote = info.vote_addrs; + (info.consensus_addrs, vote) + } + Err(_) => { + // Fallback: use provided validators with empty vote addresses + use alloy_primitives::FixedBytes; + let vote: Option>> = Some(vec![FixedBytes::ZERO; validators.len()]); + (validators.to_vec(), vote) + } + }; + + Snapshot::new(addrs, 0, genesis_header.hash_slow(), epoch_length, vote_addrs) +} + +/// Generate N funded accounts, returning (private_key, address) pairs. +fn generate_funded_accounts(count: usize) -> Vec<(B256, Address)> { + let mut accounts = Vec::with_capacity(count); + for i in 0..count { + // Deterministic key generation for reproducibility + let mut key_bytes = [0u8; 32]; + key_bytes[0] = 0x01; // prefix to avoid zero key + let idx_bytes = (i as u64 + 1).to_be_bytes(); + key_bytes[24..32].copy_from_slice(&idx_bytes); + let key = B256::from(key_bytes); + let addr = address_from_private_key(&key); + accounts.push((key, addr)); + } + accounts +} + +/// Build genesis alloc entries for funded accounts and validators. +/// Returns a map of address -> (balance, nonce, code, storage) suitable for genesis JSON. +pub fn build_funded_alloc( + funded_accounts: &[(B256, Address)], + validators: &[Address], +) -> HashMap { + let mut alloc = HashMap::new(); + let balance = U256::from(1_000_000u64) * U256::from(10u64).pow(U256::from(18)); // 1M BNB each + + for (_, addr) in funded_accounts { + alloc.insert(*addr, alloy_genesis::GenesisAccount { balance, ..Default::default() }); + } + + // Also fund validators + for addr in validators { + alloc.insert(*addr, alloy_genesis::GenesisAccount { balance, ..Default::default() }); + } + + alloc +} diff --git a/src/bench/main_entry.rs b/src/bench/main_entry.rs new file mode 100644 index 00000000..afacad32 --- /dev/null +++ b/src/bench/main_entry.rs @@ -0,0 +1,91 @@ +use crate::bench::config::{BenchConfig, Cli, Commands}; +use crate::bench::payload_job_report; +use crate::bench::payload_job_runner; +use crate::bench::report; +use crate::bench::runner; +use alloy_primitives::B256; +use clap::Parser; + +pub fn main() -> eyre::Result<()> { + let cli = Cli::parse(); + + match cli.command { + Commands::Run(args) => { + let output_path = args.output.clone(); + let label = args.label.clone(); + let config = BenchConfig::from_run_args(args)?; + + // Run inside a multi-threaded tokio runtime. + // This is needed because BscBlockBuilder::finish() calls + // tokio::runtime::Handle::try_current() for difflayer requests, + // and the real miner pipeline runs inside tokio. + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .map_err(|e| eyre::eyre!("Failed to create tokio runtime: {}", e))?; + + let timings = rt.block_on(async { + // spawn_blocking so the synchronous mining loop doesn't + // block the async executor threads + tokio::task::spawn_blocking(move || runner::run_benchmark(config)) + .await + .map_err(|e| eyre::eyre!("Task join error: {}", e))? + })?; + + report::write_csv(&timings, &output_path, &label)?; + report::print_summary(&timings, &label); + } + Commands::PayloadJobRun(args) => { + let output_path = args.output.clone(); + let label = args.label.clone(); + + let drip_config = crate::bench::payload_job_runner::TxDripConfig { + initial_tx_pct: args.initial_tx_pct, + drip_delay_ms: args.tx_drip_delay_ms, + drip_interval_ms: args.tx_drip_interval_ms, + }; + + let config = BenchConfig { + genesis_path: args.genesis, + private_keys: vec![ + parse_key("937f86f4a49cafcf81a2595c5e7afd08b875b42bf05a18aa5ebc64a0af584000"), + parse_key("ac24b6aeb63fc825b2866a5ad628c42c1c5222c56c1c9f2cedfffd95d96c75a0"), + parse_key("c73e6841e8e422048a8eafb0e8a2e62059b5d4fe9195b87d49e9b6c1c635549f"), + ], + deployer_key: parse_key( + "59ba8068eb256d520179e903f43dacf6d8d57d72bd306e1bd603fdb8c8da10e8", + ), + num_blocks: args.iterations, + txs_per_block: args.txs_per_iteration, + funded_accounts: args.funded_accounts, + background_accounts: args.background_accounts, + storage_slots_per_account: args.storage_slots_per_account, + chain_difflayers: args.chain_difflayers, + triedb: args.triedb, + output_csv: output_path.clone(), + label: label.clone(), + }; + + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .map_err(|e| eyre::eyre!("Failed to create tokio runtime: {}", e))?; + + let timings = rt.block_on(async { + payload_job_runner::run_payload_job_benchmark(config, drip_config).await + })?; + + payload_job_report::write_csv(&timings, &output_path, &label)?; + payload_job_report::print_summary(&timings, &label); + } + Commands::Compare(args) => { + report::compare(&args.baseline, &args.optimized)?; + } + } + + Ok(()) +} + +fn parse_key(hex: &str) -> B256 { + hex.parse::().expect("hardcoded key must be valid") +} diff --git a/src/bench/mod.rs b/src/bench/mod.rs new file mode 100644 index 00000000..ce666bc5 --- /dev/null +++ b/src/bench/mod.rs @@ -0,0 +1,10 @@ +pub mod config; +pub mod db_init; +pub mod main_entry; +pub mod payload_job_report; +pub mod payload_job_runner; +pub mod pool_setup; +pub mod report; +pub mod runner; +pub mod tx_gen; +pub mod validator_setup; diff --git a/src/bench/payload_job_report.rs b/src/bench/payload_job_report.rs new file mode 100644 index 00000000..9e06fb6c --- /dev/null +++ b/src/bench/payload_job_report.rs @@ -0,0 +1,153 @@ +use crate::bench::payload_job_runner::PayloadJobTiming; +use std::io::Write; +use std::path::Path; + +const CSV_HEADER: &str = "label,iteration,block_number,job_duration_us,tx_count,gas_used,\ + build_kind,exec_duration_us,trie_root_duration_us"; + +pub fn write_csv(timings: &[PayloadJobTiming], path: &Path, label: &str) -> eyre::Result<()> { + let mut file = std::fs::File::create(path)?; + writeln!(file, "{}", CSV_HEADER)?; + + for t in timings { + writeln!( + file, + "{},{},{},{},{},{},{},{},{}", + label, + t.iteration, + t.block_number, + t.job_duration_us, + t.tx_count, + t.gas_used, + t.build_kind, + t.exec_duration_us, + t.trie_root_duration_us, + )?; + } + + println!("CSV written to: {}", path.display()); + Ok(()) +} + +pub fn print_summary(timings: &[PayloadJobTiming], label: &str) { + if timings.is_empty() { + println!("No timing data for '{}'", label); + return; + } + + println!("\n{}", "=".repeat(60)); + println!(" Payload-Job Summary: {} ({} iterations)", label, timings.len()); + println!("{}\n", "=".repeat(60)); + + let job_durations: Vec = timings.iter().map(|t| t.job_duration_us).collect(); + let exec_durations: Vec = timings.iter().map(|t| t.exec_duration_us).collect(); + let trie_durations: Vec = timings.iter().map(|t| t.trie_root_duration_us).collect(); + let tx_counts: Vec = timings.iter().map(|t| t.tx_count as u128).collect(); + + println!( + "{:<22} {:>10} {:>10} {:>10} {:>10} {:>10}", + "Metric", "Mean", "P50", "P90", "P95", "P99" + ); + println!("{}", "-".repeat(75)); + + let job_stats = compute_stats(&job_durations); + println!( + "{:<22} {:>10.0} {:>10.0} {:>10.0} {:>10.0} {:>10.0}", + "job_duration (us)", + job_stats.mean, + job_stats.p50, + job_stats.p90, + job_stats.p95, + job_stats.p99 + ); + + let exec_stats = compute_stats(&exec_durations); + println!( + "{:<22} {:>10.0} {:>10.0} {:>10.0} {:>10.0} {:>10.0}", + "exec_duration (us)", + exec_stats.mean, + exec_stats.p50, + exec_stats.p90, + exec_stats.p95, + exec_stats.p99 + ); + + let trie_stats = compute_stats(&trie_durations); + println!( + "{:<22} {:>10.0} {:>10.0} {:>10.0} {:>10.0} {:>10.0}", + "trie_root (us)", + trie_stats.mean, + trie_stats.p50, + trie_stats.p90, + trie_stats.p95, + trie_stats.p99 + ); + + let tx_stats = compute_stats(&tx_counts); + println!( + "{:<22} {:>10.0} {:>10.0} {:>10.0} {:>10.0} {:>10.0}", + "tx_count", tx_stats.mean, tx_stats.p50, tx_stats.p90, tx_stats.p95, tx_stats.p99 + ); + + // Build kind breakdown + let mut kind_counts = std::collections::HashMap::new(); + for t in timings { + *kind_counts.entry(t.build_kind.clone()).or_insert(0usize) += 1; + } + println!("\n Build kind breakdown:"); + for (kind, count) in &kind_counts { + println!(" {}: {} ({:.1}%)", kind, count, *count as f64 / timings.len() as f64 * 100.0); + } + + // Success rate + let successful = timings.iter().filter(|t| t.tx_count > 0).count(); + println!( + "\n Success rate: {}/{} ({:.1}%)", + successful, + timings.len(), + successful as f64 / timings.len() as f64 * 100.0 + ); + + let total_gas: u64 = timings.iter().map(|t| t.gas_used).sum(); + let total_txs: usize = timings.iter().map(|t| t.tx_count).sum(); + println!(" Total gas: {}", total_gas); + println!(" Total txs: {}", total_txs); +} + +struct Stats { + mean: f64, + p50: f64, + p90: f64, + p95: f64, + p99: f64, +} + +fn compute_stats(values: &[u128]) -> Stats { + if values.is_empty() { + return Stats { mean: 0.0, p50: 0.0, p90: 0.0, p95: 0.0, p99: 0.0 }; + } + + let mut sorted: Vec = values.to_vec(); + sorted.sort_unstable(); + + let n = sorted.len(); + let sum: u128 = sorted.iter().sum(); + let mean = sum as f64 / n as f64; + + Stats { + mean, + p50: percentile(&sorted, 50.0), + p90: percentile(&sorted, 90.0), + p95: percentile(&sorted, 95.0), + p99: percentile(&sorted, 99.0), + } +} + +fn percentile(sorted: &[u128], pct: f64) -> f64 { + if sorted.is_empty() { + return 0.0; + } + let idx = (pct / 100.0 * (sorted.len() - 1) as f64).round() as usize; + let idx = idx.min(sorted.len() - 1); + sorted[idx] as f64 +} diff --git a/src/bench/payload_job_runner.rs b/src/bench/payload_job_runner.rs new file mode 100644 index 00000000..e65e42a8 --- /dev/null +++ b/src/bench/payload_job_runner.rs @@ -0,0 +1,46 @@ +use crate::bench::config::BenchConfig; + +/// Configuration for drip-feeding transactions mid-job to trigger retries. +#[derive(Debug, Clone, Copy)] +pub struct TxDripConfig { + /// Percentage of txs to pre-load before starting the job (0-100). + pub initial_tx_pct: u32, + /// Delay in ms before starting to drip-feed remaining txs. + pub drip_delay_ms: u64, + /// Interval in ms between drip-feed batches. + pub drip_interval_ms: u64, +} + +/// Timing record for a single payload-job iteration. +#[derive(Debug, Clone)] +pub struct PayloadJobTiming { + pub iteration: usize, + pub block_number: u64, + /// Time from job start to result received (microseconds). + pub job_duration_us: u128, + /// Transaction count in the winning payload. + pub tx_count: usize, + /// Gas used in the winning payload. + pub gas_used: u64, + /// Build kind of the winning payload. + pub build_kind: String, + /// exec_duration from BscBuiltPayload (microseconds). + pub exec_duration_us: u128, + /// trie_root_duration from BscBuiltPayload (microseconds). + pub trie_root_duration_us: u128, +} + +/// Run the payload-job benchmark. +/// +/// NOTE: This subcommand is not available on the `bench-miner-opt-split` branch +/// because the upstream refactor removed `BscPayloadJob`, `WaitSliceConfig`, +/// and related scheduling APIs. Use the `run` subcommand instead. +pub async fn run_payload_job_benchmark( + _config: BenchConfig, + _drip_config: TxDripConfig, +) -> eyre::Result> { + Err(eyre::eyre!( + "PayloadJobRun is not available on this branch. \ + Use the `run` subcommand instead." + )) +} diff --git a/src/bench/pool_setup.rs b/src/bench/pool_setup.rs new file mode 100644 index 00000000..78267825 --- /dev/null +++ b/src/bench/pool_setup.rs @@ -0,0 +1,56 @@ +use reth_primitives::TransactionSigned; +use alloy_consensus::transaction::Recovered; +use reth_transaction_pool::blobstore::InMemoryBlobStore; +use reth_transaction_pool::noop::MockTransactionValidator; +use reth_transaction_pool::{ + CoinbaseTipOrdering, EthPooledTransaction, Pool, PoolConfig, TransactionOrigin, TransactionPool, +}; + +/// The concrete pool type used in the payload-job benchmark. +pub type BenchTxPool = Pool< + MockTransactionValidator>, + CoinbaseTipOrdering>, + InMemoryBlobStore, +>; + +/// Create a fresh, empty transaction pool for the benchmark. +/// +/// Uses `minimal_protocol_basefee: 0` so low-fee benchmark transactions are accepted. +pub fn create_bench_pool() -> BenchTxPool { + let config = PoolConfig::default().with_disabled_protocol_base_fee(); + Pool::new( + MockTransactionValidator::default(), + CoinbaseTipOrdering::default(), + InMemoryBlobStore::default(), + config, + ) +} + +/// Populate the pool with pre-recovered transactions. +/// +/// Transactions are already recovered (ecrecover done during pool generation), +/// matching production where txs arrive pre-recovered from P2P. +/// +/// Returns the number of transactions that were successfully added. +pub async fn fill_pool(pool: &BenchTxPool, transactions: &[Recovered]) -> usize { + let pooled_txs: Vec<_> = transactions + .iter() + .map(|recovered| { + let encoded_length = alloy_rlp::Encodable::length(recovered.inner()); + EthPooledTransaction::new(recovered.clone(), encoded_length) + }) + .collect(); + + let total = pooled_txs.len(); + let results = pool.add_transactions(TransactionOrigin::External, pooled_txs).await; + + let ok_count = results.iter().filter(|r| r.is_ok()).count(); + let err_count = results.iter().filter(|r| r.is_err()).count(); + if err_count > 0 { + if let Some(Err(e)) = results.iter().find(|r| r.is_err()) { + eprintln!("fill_pool: {}/{} txs failed to add. First error: {:?}", err_count, total, e); + } + } + + ok_count +} diff --git a/src/bench/report.rs b/src/bench/report.rs new file mode 100644 index 00000000..6d1d3494 --- /dev/null +++ b/src/bench/report.rs @@ -0,0 +1,310 @@ +use std::collections::HashMap; +use std::io::Write; +use std::path::Path; + +/// Timing data for a single block production. +#[derive(Debug, Clone)] +pub struct BlockTiming { + pub block_number: u64, + pub validator_index: usize, + pub tx_count: usize, + pub gas_used: u64, + // Phase timings (microseconds) + pub state_setup_us: u128, + pub pre_execution_us: u128, + /// Time spent inside builder.execute_transaction() only (per-tx sum). + pub execute_only_us: u128, + /// Aggregate execution bucket (all tx execution). + pub tx_execution_us: u128, + /// Time spent inserting the built block into storage. + pub insert_block_us: u128, + /// Time spent writing the execution outcome / state changes. + pub write_state_us: u128, + /// Time spent flushing triedb/PathDB difflayers. + pub triedb_flush_us: u128, + /// Time spent committing the database transaction. + pub provider_commit_us: u128, + /// Aggregate persistence bucket = insert_block + write_state + triedb_flush + provider_commit. + pub commit_us: u128, + /// finish_with_difflayer() time: merge_transitions + hashed_state + triedb/state_root + assembly. + /// Excludes provider creation overhead (factory.latest()). + pub finish_us: u128, + pub total_us: u128, + // State metrics + pub hashed_accounts: usize, + pub hashed_storage_slots: usize, + pub has_cached_reads: bool, +} + +const CSV_HEADER: &str = "block_number,validator_index,tx_count,gas_used,\ + state_setup_us,pre_execution_us,execute_only_us,tx_execution_us,\ + insert_block_us,write_state_us,triedb_flush_us,provider_commit_us,commit_us,\ + finish_us,total_us,\ + hashed_accounts,hashed_storage_slots,has_cached_reads"; + +/// Write timing results to a CSV file. +pub fn write_csv(timings: &[BlockTiming], path: &Path, label: &str) -> eyre::Result<()> { + let mut file = std::fs::File::create(path)?; + + // Write header + writeln!(file, "label,{}", CSV_HEADER)?; + + for t in timings { + writeln!( + file, + "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", + label, + t.block_number, + t.validator_index, + t.tx_count, + t.gas_used, + t.state_setup_us, + t.pre_execution_us, + t.execute_only_us, + t.tx_execution_us, + t.insert_block_us, + t.write_state_us, + t.triedb_flush_us, + t.provider_commit_us, + t.commit_us, + t.finish_us, + t.total_us, + t.hashed_accounts, + t.hashed_storage_slots, + t.has_cached_reads, + )?; + } + + println!("CSV written to: {}", path.display()); + Ok(()) +} + +/// Read timing results from a CSV file. +pub fn read_csv(path: &Path) -> eyre::Result> { + let content = std::fs::read_to_string(path)?; + let mut timings = Vec::new(); + let mut lines = content.lines(); + + // Skip header + lines.next(); + + for line in lines { + let fields: Vec<&str> = line.split(',').collect(); + if fields.len() < 16 { + continue; + } + // Skip label field (index 0). Current layout: 19 fields. + let t = if fields.len() >= 19 { + BlockTiming { + block_number: fields[1].parse().unwrap_or(0), + validator_index: fields[2].parse().unwrap_or(0), + tx_count: fields[3].parse().unwrap_or(0), + gas_used: fields[4].parse().unwrap_or(0), + state_setup_us: fields[5].parse().unwrap_or(0), + pre_execution_us: fields[6].parse().unwrap_or(0), + execute_only_us: fields[7].parse().unwrap_or(0), + tx_execution_us: fields[8].parse().unwrap_or(0), + insert_block_us: fields[9].parse().unwrap_or(0), + write_state_us: fields[10].parse().unwrap_or(0), + triedb_flush_us: fields[11].parse().unwrap_or(0), + provider_commit_us: fields[12].parse().unwrap_or(0), + commit_us: fields[13].parse().unwrap_or(0), + finish_us: fields[14].parse().unwrap_or(0), + total_us: fields[15].parse().unwrap_or(0), + hashed_accounts: fields[16].parse().unwrap_or(0), + hashed_storage_slots: fields[17].parse().unwrap_or(0), + has_cached_reads: fields[18].parse().unwrap_or(false), + } + } else { + // Legacy format fallback + BlockTiming { + block_number: fields[1].parse().unwrap_or(0), + validator_index: fields[2].parse().unwrap_or(0), + tx_count: fields[3].parse().unwrap_or(0), + gas_used: fields[4].parse().unwrap_or(0), + state_setup_us: fields[5].parse().unwrap_or(0), + pre_execution_us: fields[6].parse().unwrap_or(0), + execute_only_us: 0, + tx_execution_us: fields[7].parse().unwrap_or(0), + insert_block_us: 0, + write_state_us: 0, + triedb_flush_us: 0, + provider_commit_us: 0, + commit_us: fields[8].parse().unwrap_or(0), + finish_us: fields[9].parse().unwrap_or(0), + total_us: fields[10].parse().unwrap_or(0), + hashed_accounts: fields.get(11).and_then(|f| f.parse().ok()).unwrap_or(0), + hashed_storage_slots: fields.get(12).and_then(|f| f.parse().ok()).unwrap_or(0), + has_cached_reads: fields.get(15).and_then(|f| f.parse().ok()).unwrap_or(false), + } + }; + timings.push(t); + } + + Ok(timings) +} + +/// Print summary statistics for a set of timings. +pub fn print_summary(timings: &[BlockTiming], label: &str) { + if timings.is_empty() { + println!("No timing data for '{}'", label); + return; + } + + println!("\n{}", "=".repeat(60)); + println!(" Summary: {} ({} blocks)", label, timings.len()); + println!("{}\n", "=".repeat(60)); + + // Collect phase values + let phases: Vec<(&str, Vec)> = vec![ + ("state_setup", timings.iter().map(|t| t.state_setup_us).collect()), + ("pre_execution", timings.iter().map(|t| t.pre_execution_us).collect()), + ("execute_only", timings.iter().map(|t| t.execute_only_us).collect()), + ("tx_execution", timings.iter().map(|t| t.tx_execution_us).collect()), + ("insert_block", timings.iter().map(|t| t.insert_block_us).collect()), + ("write_state", timings.iter().map(|t| t.write_state_us).collect()), + ("triedb_flush", timings.iter().map(|t| t.triedb_flush_us).collect()), + ("provider_commit", timings.iter().map(|t| t.provider_commit_us).collect()), + ("finish (root+asm)", timings.iter().map(|t| t.finish_us).collect()), + ("commit (mdbx)", timings.iter().map(|t| t.commit_us).collect()), + ("TOTAL", timings.iter().map(|t| t.total_us).collect()), + ]; + + println!( + "{:<20} {:>10} {:>10} {:>10} {:>10} {:>10}", + "Phase", "Mean(us)", "P50(us)", "P90(us)", "P95(us)", "P99(us)" + ); + println!("{}", "-".repeat(80)); + + for (name, values) in &phases { + let stats = compute_stats(values); + println!( + "{:<20} {:>10.0} {:>10.0} {:>10.0} {:>10.0} {:>10.0}", + name, stats.mean, stats.p50, stats.p90, stats.p95, stats.p99 + ); + } + + // Throughput + let total_time_s = timings.iter().map(|t| t.total_us).sum::() as f64 / 1_000_000.0; + let total_gas: u64 = timings.iter().map(|t| t.gas_used).sum(); + let total_txs: usize = timings.iter().map(|t| t.tx_count).sum(); + + println!("\n Throughput:"); + println!(" Blocks/sec: {:.1}", timings.len() as f64 / total_time_s); + println!(" TX/sec: {:.0}", total_txs as f64 / total_time_s); + println!(" Gas/sec: {:.0}", total_gas as f64 / total_time_s); + println!(" Total gas: {}", total_gas); + println!(" Total txs: {}", total_txs); +} + +/// Compare two benchmark runs side-by-side. +pub fn compare(baseline_path: &Path, optimized_path: &Path) -> eyre::Result<()> { + let baseline = read_csv(baseline_path)?; + let optimized = read_csv(optimized_path)?; + + println!("\n=== A/B Comparison ===\n"); + + print_summary(&baseline, "Baseline"); + print_summary(&optimized, "Optimized"); + + // Side-by-side comparison + let phases = [ + "state_setup", + "pre_execution", + "execute_only", + "tx_execution", + "insert_block", + "write_state", + "triedb_flush", + "provider_commit", + "finish", + "commit", + "TOTAL", + ]; + + let baseline_means = phase_means(&baseline); + let optimized_means = phase_means(&optimized); + + println!( + "\n{:<20} {:>12} {:>12} {:>10}", + "Phase", "Baseline(us)", "Optimized(us)", "Change(%)" + ); + println!("{}", "-".repeat(60)); + + for phase in &phases { + let b = baseline_means.get(*phase).copied().unwrap_or(0.0); + let o = optimized_means.get(*phase).copied().unwrap_or(0.0); + let pct = if b > 0.0 { ((o - b) / b) * 100.0 } else { 0.0 }; + let indicator = if pct < -1.0 { + " FASTER" + } else if pct > 1.0 { + " SLOWER" + } else { + "" + }; + println!("{:<20} {:>12.0} {:>12.0} {:>+9.1}%{}", phase, b, o, pct, indicator); + } + + Ok(()) +} + +fn phase_means(timings: &[BlockTiming]) -> HashMap<&'static str, f64> { + let n = timings.len() as f64; + if n == 0.0 { + return HashMap::new(); + } + let mut m = HashMap::new(); + m.insert("state_setup", timings.iter().map(|t| t.state_setup_us as f64).sum::() / n); + m.insert("pre_execution", timings.iter().map(|t| t.pre_execution_us as f64).sum::() / n); + m.insert("execute_only", timings.iter().map(|t| t.execute_only_us as f64).sum::() / n); + m.insert("tx_execution", timings.iter().map(|t| t.tx_execution_us as f64).sum::() / n); + m.insert("insert_block", timings.iter().map(|t| t.insert_block_us as f64).sum::() / n); + m.insert("write_state", timings.iter().map(|t| t.write_state_us as f64).sum::() / n); + m.insert("triedb_flush", timings.iter().map(|t| t.triedb_flush_us as f64).sum::() / n); + m.insert( + "provider_commit", + timings.iter().map(|t| t.provider_commit_us as f64).sum::() / n, + ); + m.insert("finish", timings.iter().map(|t| t.finish_us as f64).sum::() / n); + m.insert("commit", timings.iter().map(|t| t.commit_us as f64).sum::() / n); + m.insert("TOTAL", timings.iter().map(|t| t.total_us as f64).sum::() / n); + m +} + +struct Stats { + mean: f64, + p50: f64, + p90: f64, + p95: f64, + p99: f64, +} + +fn compute_stats(values: &[u128]) -> Stats { + if values.is_empty() { + return Stats { mean: 0.0, p50: 0.0, p90: 0.0, p95: 0.0, p99: 0.0 }; + } + + let mut sorted: Vec = values.to_vec(); + sorted.sort_unstable(); + + let n = sorted.len(); + let sum: u128 = sorted.iter().sum(); + let mean = sum as f64 / n as f64; + + Stats { + mean, + p50: percentile(&sorted, 50.0), + p90: percentile(&sorted, 90.0), + p95: percentile(&sorted, 95.0), + p99: percentile(&sorted, 99.0), + } +} + +fn percentile(sorted: &[u128], pct: f64) -> f64 { + if sorted.is_empty() { + return 0.0; + } + let idx = (pct / 100.0 * (sorted.len() - 1) as f64).round() as usize; + let idx = idx.min(sorted.len() - 1); + sorted[idx] as f64 +} diff --git a/src/bench/runner.rs b/src/bench/runner.rs new file mode 100644 index 00000000..4021797e --- /dev/null +++ b/src/bench/runner.rs @@ -0,0 +1,463 @@ +use crate::bench::config::BenchConfig; +use crate::bench::db_init; +use crate::bench::report::BlockTiming; +use crate::bench::tx_gen; +use crate::bench::validator_setup; +use crate::node::evm::config::{BscEvmConfig, BscNextBlockEnvAttributes}; +use crate::node::evm::util::insert_header_to_cache; +use crate::node::miner::bsc_miner::MiningContext; +use crate::node::miner::signer::init_global_signer; +use crate::node::miner::util::prepare_new_attributes; + +use alloy_consensus::transaction::Recovered; +use reth_evm::execute::{BlockBuilder, BlockBuilderOutcome}; +use reth_evm::{ConfigureEvm, NextBlockEnvAttributes}; +use reth_payload_primitives::PayloadBuilderAttributes; +use reth_primitives::SealedHeader; +use reth_primitives_traits::SignerRecoverable; +use reth_provider::{ + AccountReader, BlockWriter, DBProvider, DatabaseProviderFactory, ExecutionOutcome, + OriginalValuesKnown, StateWriteConfig, StateWriter, +}; +use reth_revm::cached::CachedReads; +use reth_revm::database::StateProviderDatabase; +use revm::database::State; +use std::sync::Arc; +use std::time::Instant; + +/// Run the full miner pipeline benchmark. +pub fn run_benchmark(config: BenchConfig) -> eyre::Result> { + println!("=== BSC Execution/State-Root Microbenchmark ==="); + println!( + "Blocks: {}, TXs/block: {}, Funded accounts: {}", + config.num_blocks, config.txs_per_block, config.funded_accounts + ); + + // 1. Initialize infrastructure (parlia, snapshot, header cache, MDBX + ProviderFactory) + println!("\n[1/6] Initializing infrastructure from genesis..."); + let init = db_init::init_benchmark(&config)?; + + let chain_id = init.chain_spec.inner.chain.id(); + let evm_config = BscEvmConfig::new(init.chain_spec.clone()); + + // Initialize global signer for block sealing (first validator) + init_global_signer(config.private_keys[0]) + .map_err(|e| eyre::eyre!("Failed to init global signer: {}", e))?; + + // 2. TrieDB status (initialized in db_init if --triedb was set) + if config.triedb { + println!("\n[2/6] TrieDB enabled (initialized during genesis)"); + } else { + println!("\n[2/6] TrieDB disabled (use --triedb to enable)"); + } + if config.chain_difflayers { + println!( + " NOTE: --chain-difflayers is ignored on this branch: the current builder API does not expose difflayer chaining." + ); + } + + // 3. Verify genesis state is readable from MDBX + println!("\n[3/6] Verifying genesis state in MDBX..."); + { + let state_provider = init + .factory + .latest() + .map_err(|e| eyre::eyre!("Failed to get latest state after genesis: {}", e))?; + // Quick sanity check: deployer account should exist + let deployer_addr = db_init::address_from_private_key(&config.deployer_key); + let acct = state_provider + .basic_account(&deployer_addr) + .map_err(|e| eyre::eyre!("Failed to query deployer account: {}", e))?; + if let Some(a) = &acct { + println!(" Deployer {} balance: {}", deployer_addr, a.balance); + } else { + println!(" WARNING: Deployer {} not found in genesis state", deployer_addr); + } + } + + // 4. Generate BLS keys and createValidator transactions + println!("\n[4/6] Generating BLS keys and registering validators..."); + let (create_val_txs, _bls_keys) = validator_setup::create_all_validator_txs( + &config.private_keys, + &init.validator_addresses, + chain_id, + ); + println!(" Generated {} createValidator transactions", create_val_txs.len()); + + // 5. Deploy ERC20 and prepare distribution transactions + println!("\n[5/6] Preparing ERC20 deployment and distribution..."); + let deployer_key = &config.deployer_key; + let (deploy_tx, erc20_address) = tx_gen::erc20_deploy_tx(deployer_key, 0, chain_id); + println!(" ERC20 contract will be at: {}", erc20_address); + + let distribution_txs = tx_gen::erc20_distribution_txs( + deployer_key, + &init.funded_accounts, + erc20_address, + 1, // deployer nonce 1 (after deploy tx at nonce 0) + chain_id, + ); + println!(" Generated {} distribution transactions", distribution_txs.len()); + + // Pre-recover setup txs (createValidator + deploy + distribution) + let setup_txs: Vec> = { + let mut txs = Vec::new(); + for tx in &create_val_txs { + if let Ok(r) = tx.clone().try_into_recovered() { + txs.push(r); + } + } + txs.push(deploy_tx); + txs.extend(distribution_txs); + txs + }; + + // 6. Pre-generate benchmark transaction pool + println!( + "\n[6/6] Generating transaction pool ({} ERC20 transfers)...", + config.num_blocks * config.txs_per_block + ); + let tx_pool = tx_gen::generate_tx_pool( + &init.funded_accounts, + config.num_blocks, + config.txs_per_block, + chain_id, + erc20_address, + ); + + // === Execute blocks === + let mut timings = Vec::with_capacity(config.num_blocks); + let mut parent_header = init.genesis_header.clone(); + let mut parent_snapshot = init.genesis_snapshot.clone(); + let mut cached_reads: Option = None; + + let turn_length = parent_snapshot.turn_length.unwrap_or(1) as usize; + let num_validators = init.validator_addresses.len(); + + // Total blocks: 1 setup + N benchmark + let total_blocks = config.num_blocks + 1; + + for block_idx in 0..total_blocks { + let block_number = block_idx as u64 + 1; + let is_setup_block = block_idx == 0; + + // Determine the in-turn validator using Parlia rotation logic + let validator_index = determine_validator_index(block_number, num_validators, turn_length); + let validator_addr = init.validator_addresses[validator_index]; + + let has_cached_reads = cached_reads.is_some(); + + let block_start = Instant::now(); + + // Create MiningContext + let mut mining_ctx = MiningContext { + header: None, + parent_header: parent_header.clone(), + parent_snapshot: Arc::new(parent_snapshot.clone()), + is_inturn: true, + cached_reads: None, + }; + + // Prepare attributes + let attributes = prepare_new_attributes( + &mut mining_ctx, + init.parlia.clone(), + &parent_header, + validator_addr, + ); + + // TIME: State setup from MDBX + let state_setup_start = Instant::now(); + + // Get the current state from the MDBX database. + // After genesis init or each committed block, latest() returns the correct parent state. + let state_provider = init + .factory + .latest() + .map_err(|e| eyre::eyre!("Failed to get state for block {}: {:?}", block_number, e))?; + + // Wrap state provider for the EVM State DB + let state_db = StateProviderDatabase::new(&*state_provider); + + // Build State with CachedReads (matches the real miner pipeline exactly) + let mut cached = cached_reads.take().unwrap_or_default(); + let mut db = + State::builder().with_database(cached.as_db_mut(state_db)).with_bundle_update().build(); + + let state_setup_us = state_setup_start.elapsed().as_micros(); + + // Build the block using the EVM config pipeline + let pre_exec_start = Instant::now(); + + let mut builder = evm_config + .builder_for_next_block( + &mut db, + &parent_header, + BscNextBlockEnvAttributes { + inner: NextBlockEnvAttributes { + timestamp: attributes.timestamp(), + suggested_fee_recipient: attributes.suggested_fee_recipient(), + prev_randao: attributes.prev_randao(), + gas_limit: parent_header.gas_limit, + parent_beacon_block_root: attributes.parent_beacon_block_root(), + withdrawals: Some(attributes.withdrawals().clone()), + extra_data: Default::default(), + }, + parent_difflayers: None, + triedb_prefetcher: None, + validator_cache_sink: None, + turn_length_sink: None, + }, + ) + .map_err(|e| { + eyre::eyre!("Failed to create block builder for block {}: {:?}", block_number, e) + })?; + + // Apply pre-execution changes (system contract calls) + builder + .apply_pre_execution_changes() + .map_err(|e| eyre::eyre!("Pre-execution failed for block {}: {:?}", block_number, e))?; + let pre_execution_us = pre_exec_start.elapsed().as_micros(); + + // TIME: Transaction execution + // Txs are pre-recovered (ecrecover done during pool generation, matching production + // where txs arrive pre-recovered from P2P mempool). + let tx_exec_start = Instant::now(); + let mut execute_only_us = 0u128; + let mut tx_count = 0u64; + let mut gas_used = 0u64; + + if is_setup_block { + // Block 0 (setup): createValidator + ERC20 deploy + distribution + for recovered in setup_txs.iter().cloned() { + let execute_start = Instant::now(); + match builder.execute_transaction(recovered) { + Ok(g) => { + tx_count += 1; + gas_used += g; + } + Err(e) => { + tracing::trace!("Setup tx failed: {:?}", e); + } + } + execute_only_us += execute_start.elapsed().as_micros(); + } + } else { + // Benchmark blocks: execute ERC20 transfers from the pre-recovered tx pool + let pool_idx = block_idx - 1; // block_idx 1 -> pool index 0 + let selected_txs = tx_pool.blocks.get(pool_idx).map(Vec::as_slice).unwrap_or(&[]); + + for recovered in selected_txs.iter().cloned() { + let execute_start = Instant::now(); + match builder.execute_transaction(recovered) { + Ok(g) => { + tx_count += 1; + gas_used += g; + } + Err(e) => { + tracing::trace!("TX execution failed: {:?}", e); + } + } + execute_only_us += execute_start.elapsed().as_micros(); + } + } + let tx_execution_us = tx_exec_start.elapsed().as_micros(); + + // TIME: Finish (post-exec + state root + assembly) + // Get a separate state provider BEFORE timing starts to exclude MDBX overhead + // (production finalize timing in payload.rs:623-625 doesn't include provider creation). + let finish_state_provider = init.factory.latest().map_err(|e| { + eyre::eyre!("Failed to get finish state for block {}: {:?}", block_number, e) + })?; + + let finish_start = Instant::now(); + + // This branch only exposes `finish()`. It computes a real state root against the + // configured state backend, but it does not return difflayers for warm-chain reuse. + let outcome = builder + .finish(&*finish_state_provider) + .map_err(|e| eyre::eyre!("Block {} finish failed: {:?}", block_number, e))?; + + let finish_us = finish_start.elapsed().as_micros(); + + // Extract metrics from the outcome before committing + let hashed_accounts = outcome.hashed_state.accounts.len(); + let hashed_storage_slots: usize = + outcome.hashed_state.storages.values().map(|s| s.storage.len()).sum(); + + let BlockBuilderOutcome { execution_result, block: recovered_block, .. } = outcome; + + // Get the block header info we need before consuming the block + let new_header = recovered_block.header().clone(); + let new_hash = new_header.hash_slow(); + let state_root = new_header.state_root; + + // Get a read-write database provider for committing + let provider_rw = init.factory.database_provider_rw().map_err(|e| { + eyre::eyre!("Failed to get provider_rw for block {}: {:?}", block_number, e) + })?; + let commit_start = Instant::now(); + let mut triedb_flush_us = 0u128; + + // Insert the block into the database + let insert_block_start = Instant::now(); + provider_rw + .insert_block(&recovered_block) + .map_err(|e| eyre::eyre!("Failed to insert block {}: {:?}", block_number, e))?; + let insert_block_us = insert_block_start.elapsed().as_micros(); + + // Extract cache from bundle_state before take_bundle() consumes it. + // This mirrors production's cache_for_next() pattern (bsc_miner.rs:331-351). + let mut new_cached = CachedReads::default(); + for (addr, acc) in db.bundle_state.state.iter() { + if let Some(info) = acc.info.clone() { + let storage = + acc.storage.iter().map(|(key, slot)| (*key, slot.present_value)).collect(); + new_cached.insert_account(*addr, info, storage); + } + } + + // Build ExecutionOutcome from the bundle state and write it + let execution_outcome = ExecutionOutcome::new( + db.take_bundle(), + vec![execution_result.receipts], + block_number, + vec![execution_result.requests], + ); + + let write_state_start = Instant::now(); + provider_rw + .write_state(&execution_outcome, OriginalValuesKnown::No, StateWriteConfig::default()) + .map_err(|e| { + eyre::eyre!("Failed to write state for block {}: {:?}", block_number, e) + })?; + let write_state_us = write_state_start.elapsed().as_micros(); + + if config.triedb { + let mut triedb = rust_eth_triedb::get_global_triedb(); + let triedb_flush_start = Instant::now(); + triedb.flush(block_number, state_root, &None).map_err(|e| { + eyre::eyre!("Failed to flush triedb for block {}: {:?}", block_number, e) + })?; + triedb_flush_us = triedb_flush_start.elapsed().as_micros(); + } + + // Commit the transaction (static files + DB) + let provider_commit_start = Instant::now(); + provider_rw + .commit() + .map_err(|e| eyre::eyre!("Failed to commit block {}: {:?}", block_number, e))?; + let provider_commit_us = provider_commit_start.elapsed().as_micros(); + + let commit_us = commit_start.elapsed().as_micros(); + let total_us = block_start.elapsed().as_micros(); + + // Populate CachedReads for next block from execution outcome + cached_reads = Some(new_cached); + + // Update chain tip + let new_sealed = SealedHeader::new(new_header.clone(), new_hash); + insert_header_to_cache(new_header); + + parent_header = new_sealed; + parent_snapshot.block_number = block_number; + parent_snapshot.block_hash = new_hash; + + if is_setup_block { + // Setup block -- do NOT record timing + println!( + " Setup block 0 complete: {} txs, {} gas used, {}us total (commit: {}us)", + tx_count, gas_used, total_us, commit_us + ); + continue; + } + + // Record timing for benchmark blocks + let timing = BlockTiming { + block_number, + validator_index, + tx_count: tx_count as usize, + gas_used, + state_setup_us, + pre_execution_us, + execute_only_us, + tx_execution_us, + insert_block_us, + write_state_us, + triedb_flush_us, + provider_commit_us, + commit_us, + finish_us, + total_us, + hashed_accounts, + hashed_storage_slots, + has_cached_reads, + }; + + if block_number.is_multiple_of(10) || block_number <= 2 { + let flags = if has_cached_reads { "C" } else { "-" }; + println!( + " Block {:>4} | v[{}] {} | txs: {:>3} | gas: {:>8} | finish: {:>6}us | commit: {:>6}us | total: {:>6}us", + block_number, + validator_index, + flags, + tx_count, + gas_used, + finish_us, + commit_us, + total_us, + ); + } + + timings.push(timing); + } + + Ok(timings) +} + +/// Determine which validator is in-turn for a given block number. +fn determine_validator_index( + block_number: u64, + num_validators: usize, + turn_length: usize, +) -> usize { + let turn = (block_number.saturating_sub(1) / turn_length as u64) as usize; + turn % num_validators +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_validator_rotation() { + assert_eq!(determine_validator_index(1, 3, 1), 0); + assert_eq!(determine_validator_index(2, 3, 1), 1); + assert_eq!(determine_validator_index(3, 3, 1), 2); + assert_eq!(determine_validator_index(4, 3, 1), 0); + + assert_eq!(determine_validator_index(1, 3, 2), 0); + assert_eq!(determine_validator_index(2, 3, 2), 0); + assert_eq!(determine_validator_index(3, 3, 2), 1); + assert_eq!(determine_validator_index(4, 3, 2), 1); + assert_eq!(determine_validator_index(5, 3, 2), 2); + assert_eq!(determine_validator_index(6, 3, 2), 2); + assert_eq!(determine_validator_index(7, 3, 2), 0); + } + + #[test] + #[ignore] // Run with: cargo test --features bench-test -p reth_bsc bench::runner::tests::decrypt_dev_keystores -- --ignored --nocapture + fn decrypt_dev_keystores() { + let keystores = [ + "/Users/user/development/node-deploy/.local/node0/keystore/UTC--2024-05-10T03-37-35.756992000Z--bcdd0d2cda5f6423e57b6a4dcd75decbe31aecf0", + "/Users/user/development/node-deploy/.local/node1/keystore/UTC--2024-05-10T03-37-36.999615000Z--bbd1acc20bd8304309d31d8fd235210d0efc049d", + "/Users/user/development/node-deploy/.local/node2/keystore/UTC--2024-05-10T03-37-38.188296000Z--5e2a531a825d8b61bcc305a35a7433e9a8920f0f", + ]; + let password = "0123456789"; + + for (i, path) in keystores.iter().enumerate() { + let pk = eth_keystore::decrypt_key(path, password).expect("decrypt failed"); + println!("Validator {} private key: {}", i, hex::encode(&pk)); + } + } +} diff --git a/src/bench/tx_gen.rs b/src/bench/tx_gen.rs new file mode 100644 index 00000000..270e63bd --- /dev/null +++ b/src/bench/tx_gen.rs @@ -0,0 +1,207 @@ +use crate::node::miner::signer::MinerSigner; +use alloy_consensus::Transaction as TxTrait; +use alloy_consensus::TxLegacy; +use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; +use alloy_sol_macro::sol; +use alloy_sol_types::SolCall; +use rand::Rng; +use reth_primitives::{Transaction, TransactionSigned}; +use alloy_consensus::transaction::Recovered; +use reth_primitives_traits::SignerRecoverable; +use secp256k1::SecretKey; +use std::collections::HashMap; + +// Simple ERC20 contract - minimal implementation for benchmarking +sol! { + #[allow(missing_docs)] + function transfer(address to, uint256 amount) returns (bool); + function balanceOf(address account) returns (uint256); +} + +/// The ERC20 bytecode - a minimal token contract. +/// This is compiled from a simple Solidity ERC20 with mint in constructor. +/// We use a well-known minimal ERC20 bytecode for the benchmark. +pub const SIMPLE_ERC20_BYTECODE: &str = concat!( + // Constructor: stores msg.sender balance as max uint + // Runtime: supports transfer(address,uint256) and balanceOf(address) + "608060405234801561001057600080fd5b50", + "336000908152602081905260408120", + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9055", + "6101e7806100456000396000f3fe", + "608060405234801561001057600080fd5b50", + "600436106100365760003560e01c806370a08231", + "1461003b578063a9059cbb14610061575b600080fd5b", + "61004e610049366004610152565b610081565b604051908152602001", + "60405180910390f35b61007461006f366004610174565b61009e565b", + "604051901515815260200160405180910390f35b", + "6001600160a01b031660009081526020819052604090205490565b", + "600080336001600160a01b0316815260208190526040812054", + "83811015610100576040517f08c379a0000000000000000000000000", + "000000000000000000000000000000008152600401", + "6100f790602080825260049082015263189a5b9960e21b604082015260600190565b", + "60405180910390fd5b336000908152602081905260408082208583900390556001600160a01b03", + "8516825281208054850190556001915050610148565b92915050565b", + "60006020828403121561015f57600080fd5b8135", + "6001600160a01b038116811461014857600080fd5b", + "6000806040838503121561018757600080fd5b8235", + "6001600160a01b038116811461019b57600080fd5b94602093909301359350505056fea264" +); + +/// Pre-generated pool of pre-recovered transactions. +/// +/// Transactions are recovered (ecrecover) eagerly during pool generation so that the +/// benchmark loop only measures block-building work — matching production where txs arrive +/// pre-recovered from the P2P mempool. +pub struct TxPool { + /// Transactions grouped by block. Each entry is a Vec of pre-recovered txs for one block. + pub blocks: Vec>>, + /// ERC20 contract address (deployed in genesis or block 0) + pub erc20_address: Address, +} + +/// Generate the transaction pool for the benchmark. +/// +/// Creates `num_blocks` batches of `txs_per_block` transactions. +/// All transactions are ERC20 transfer() calls between funded accounts. +pub fn generate_tx_pool( + funded_accounts: &[(B256, Address)], + num_blocks: usize, + txs_per_block: usize, + chain_id: u64, + erc20_address: Address, +) -> TxPool { + let mut rng = rand::rng(); + let num_accounts = funded_accounts.len(); + + // Track nonces per account + let mut nonces: HashMap = HashMap::new(); + for (_, addr) in funded_accounts { + nonces.insert(*addr, 0); + } + + let mut blocks = Vec::with_capacity(num_blocks); + + for _block_idx in 0..num_blocks { + let mut block_txs = Vec::with_capacity(txs_per_block); + + for _tx_idx in 0..txs_per_block { + // Pick random sender and receiver (different accounts) + let sender_idx = rng.random_range(0..num_accounts); + let mut receiver_idx = rng.random_range(0..num_accounts); + while receiver_idx == sender_idx { + receiver_idx = rng.random_range(0..num_accounts); + } + + let (sender_key, sender_addr) = &funded_accounts[sender_idx]; + let (_, receiver_addr) = &funded_accounts[receiver_idx]; + let nonce = nonces.get_mut(sender_addr).unwrap(); + + // Create ERC20 transfer call + let amount = U256::from(rng.random_range(1u64..1000)); + let calldata = transferCall { to: *receiver_addr, amount }.abi_encode(); + + let tx = Transaction::Legacy(TxLegacy { + chain_id: Some(chain_id), + nonce: *nonce, + gas_limit: 60_000, // ERC20 transfer typically uses ~50k gas + gas_price: 1, + value: U256::ZERO, + input: Bytes::from(calldata), + to: TxKind::Call(erc20_address), + }); + + // Sign the transaction + let sk = SecretKey::from_slice(sender_key.as_ref()).expect("valid key"); + let signer = MinerSigner::new(sk); + let signed = signer.sign_transaction(tx).expect("signing failed"); + + *nonce += 1; + + // Pre-recover immediately (mirrors production: txs enter mempool pre-recovered) + let recovered = signed.try_into_recovered().expect("just-signed tx must recover"); + block_txs.push(recovered); + } + + // Sort by (sender, nonce) so the EVM processes each sender's txs in order. + // No ecrecover needed — signer is already cached in Recovered. + block_txs.sort_by(|a, b| { + a.signer().cmp(&b.signer()).then(a.nonce().cmp(&b.nonce())) + }); + + blocks.push(block_txs); + } + + println!( + "Generated {} blocks x {} txs = {} total ERC20 transfers", + num_blocks, + txs_per_block, + num_blocks * txs_per_block + ); + + TxPool { blocks, erc20_address } +} + +/// Get the deploy transaction for a simple ERC20 contract. +/// The deployer gets max balance minted in the constructor. +pub fn erc20_deploy_tx( + deployer_key: &B256, + nonce: u64, + chain_id: u64, +) -> (Recovered, Address) { + let bytecode = hex::decode(SIMPLE_ERC20_BYTECODE).expect("valid hex bytecode"); + + let tx = Transaction::Legacy(TxLegacy { + chain_id: Some(chain_id), + nonce, + gas_limit: 500_000, + gas_price: 1, + value: U256::ZERO, + input: Bytes::from(bytecode), + to: TxKind::Create, + }); + + let sk = SecretKey::from_slice(deployer_key.as_ref()).expect("valid key"); + let signer = MinerSigner::new(sk); + let signed = signer.sign_transaction(tx).expect("signing failed"); + let recovered = signed.try_into_recovered().expect("just-signed tx must recover"); + + // Compute contract address: keccak256(rlp([sender, nonce]))[12..] + let deployer_addr = crate::bench::db_init::address_from_private_key(deployer_key); + let contract_addr = deployer_addr.create(nonce); + + (recovered, contract_addr) +} + +/// Create ERC20 transfer transactions to distribute initial tokens to all funded accounts. +/// The deployer (who owns all tokens from constructor) sends tokens to each account. +pub fn erc20_distribution_txs( + deployer_key: &B256, + funded_accounts: &[(B256, Address)], + erc20_address: Address, + start_nonce: u64, + chain_id: u64, +) -> Vec> { + let sk = SecretKey::from_slice(deployer_key.as_ref()).expect("valid key"); + let signer = MinerSigner::new(sk); + let mut txs = Vec::with_capacity(funded_accounts.len()); + let distribution_amount = U256::from(1_000_000_000u64); // 1B tokens each + + for (i, (_, addr)) in funded_accounts.iter().enumerate() { + let calldata = transferCall { to: *addr, amount: distribution_amount }.abi_encode(); + + let tx = Transaction::Legacy(TxLegacy { + chain_id: Some(chain_id), + nonce: start_nonce + i as u64, + gas_limit: 60_000, + gas_price: 1, + value: U256::ZERO, + input: Bytes::from(calldata), + to: TxKind::Call(erc20_address), + }); + + let signed = signer.sign_transaction(tx).expect("signing failed"); + txs.push(signed.try_into_recovered().expect("just-signed tx must recover")); + } + + txs +} diff --git a/src/bench/validator_setup.rs b/src/bench/validator_setup.rs new file mode 100644 index 00000000..5f60b215 --- /dev/null +++ b/src/bench/validator_setup.rs @@ -0,0 +1,148 @@ +use crate::node::miner::signer::MinerSigner; +use alloy_consensus::TxLegacy; +use alloy_primitives::{Address, Bytes, Keccak256, TxKind, U256}; +use alloy_sol_macro::sol; +use alloy_sol_types::SolCall; +use blst::min_pk::SecretKey as BlsSecretKey; +use reth_primitives::{Transaction, TransactionSigned}; +use secp256k1::SecretKey; + +/// StakeHub contract address +const STAKE_HUB: Address = Address::new([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x02, +]); + +/// Delegation amount: 20001 BNB (matches create-validator script) +const DELEGATION_AMOUNT: u128 = 20_001u128 * 1_000_000_000_000_000_000u128; + +sol! { + #[allow(missing_docs)] + struct Commission { + uint64 rate; + uint64 maxRate; + uint64 maxChangeRate; + } + + #[allow(missing_docs)] + struct Description { + string moniker; + string identity; + string website; + string details; + } + + #[allow(missing_docs)] + function createValidator( + address consensusAddress, + bytes voteAddress, + bytes blsProof, + Commission commission, + Description description + ) payable; +} + +/// Generated BLS key pair for a validator +pub struct ValidatorBlsKey { + pub secret: BlsSecretKey, + pub pubkey_bytes: Vec, +} + +/// Generate a deterministic BLS key pair for a validator index. +pub fn generate_bls_key(validator_index: usize) -> ValidatorBlsKey { + // Deterministic seed for reproducibility + let mut ikm = [0u8; 32]; + ikm[0] = 0xBE; // prefix + ikm[31] = validator_index as u8; + let secret = BlsSecretKey::key_gen(&ikm, &[]).expect("valid BLS key"); + let pk = secret.sk_to_pk(); + let pubkey_bytes = pk.compress().to_vec(); + ValidatorBlsKey { secret, pubkey_bytes } +} + +/// Create the BLS proof for createValidator. +/// proof = BLS_sign(keccak256(consensusAddr || blsPubKey || paddedChainId)) +fn create_bls_proof( + bls_secret: &BlsSecretKey, + consensus_addr: Address, + bls_pubkey: &[u8], + chain_id: u64, +) -> Vec { + let mut chain_id_padded = [0u8; 32]; + chain_id_padded[24..32].copy_from_slice(&chain_id.to_be_bytes()); + + let mut hasher = Keccak256::new(); + hasher.update(consensus_addr.as_slice()); + hasher.update(bls_pubkey); + hasher.update(chain_id_padded); + let msg_hash = hasher.finalize(); + + let dst = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + let sig = bls_secret.sign(msg_hash.as_slice(), dst, &[]); + sig.compress().to_vec() +} + +/// Build the createValidator transaction for a single validator. +/// The validator signs it themselves (msg.sender == consensusAddress). +pub fn create_validator_tx( + validator_key: &alloy_primitives::B256, + validator_addr: Address, + bls_key: &ValidatorBlsKey, + chain_id: u64, + nonce: u64, +) -> TransactionSigned { + let proof = create_bls_proof(&bls_key.secret, validator_addr, &bls_key.pubkey_bytes, chain_id); + + let calldata = createValidatorCall { + consensusAddress: validator_addr, + voteAddress: Bytes::from(bls_key.pubkey_bytes.clone()), + blsProof: Bytes::from(proof), + commission: Commission { rate: 100, maxRate: 1000, maxChangeRate: 100 }, + description: Description { + moniker: format!("BenchVal{}", nonce), + identity: String::new(), + website: String::new(), + details: String::new(), + }, + } + .abi_encode(); + + let tx = Transaction::Legacy(TxLegacy { + chain_id: Some(chain_id), + nonce, + gas_limit: 2_000_000, + gas_price: 1, + value: U256::from(DELEGATION_AMOUNT), + input: Bytes::from(calldata), + to: TxKind::Call(STAKE_HUB), + }); + + let sk = SecretKey::from_slice(validator_key.as_ref()).expect("valid key"); + let signer = MinerSigner::new(sk); + signer.sign_transaction(tx).expect("signing failed") +} + +/// Generate BLS keys and createValidator transactions for all 3 validators. +pub fn create_all_validator_txs( + validator_keys: &[alloy_primitives::B256], + validator_addrs: &[Address], + chain_id: u64, +) -> (Vec, Vec) { + let mut txs = Vec::new(); + let mut bls_keys = Vec::new(); + + for (i, (key, addr)) in validator_keys.iter().zip(validator_addrs.iter()).enumerate() { + let bls_key = generate_bls_key(i); + let tx = create_validator_tx(key, *addr, &bls_key, chain_id, 0); + println!( + " Validator {}: addr={}, bls_pubkey={}...", + i, + addr, + hex::encode(&bls_key.pubkey_bytes[..8]) + ); + txs.push(tx); + bls_keys.push(bls_key); + } + + (txs, bls_keys) +} diff --git a/src/bench_main.rs b/src/bench_main.rs new file mode 100644 index 00000000..37f2ca60 --- /dev/null +++ b/src/bench_main.rs @@ -0,0 +1,3 @@ +fn main() -> eyre::Result<()> { + reth_bsc::bench::main_entry::main() +} diff --git a/src/chainspec/bootnode_override.rs b/src/chainspec/bootnode_override.rs index 18d5b5df..c76b91be 100644 --- a/src/chainspec/bootnode_override.rs +++ b/src/chainspec/bootnode_override.rs @@ -1,15 +1,14 @@ -use std::sync::OnceLock; -use reth_discv4::NodeRecord; use eyre::Result; +use reth_discv4::NodeRecord; +use std::sync::OnceLock; /// Global storage for bootnode override static BOOTNODE_OVERRIDE: OnceLock>> = OnceLock::new(); /// Set the global bootnode override pub fn set_bootnode_override(bootnodes: Option>) -> Result<()> { - BOOTNODE_OVERRIDE.set(bootnodes) - .map_err(|_| eyre::eyre!("Bootnode override already set"))?; - + BOOTNODE_OVERRIDE.set(bootnodes).map_err(|_| eyre::eyre!("Bootnode override already set"))?; + Ok(()) } @@ -21,4 +20,4 @@ pub fn get_bootnode_override() -> &'static Option> { /// Check if bootnode override is active pub fn has_bootnode_override() -> bool { BOOTNODE_OVERRIDE.get().is_some_and(|nodes| nodes.is_some()) -} \ No newline at end of file +} diff --git a/src/chainspec/bsc_rialto.rs b/src/chainspec/bsc_rialto.rs index c3fde534..34052d74 100644 --- a/src/chainspec/bsc_rialto.rs +++ b/src/chainspec/bsc_rialto.rs @@ -1,5 +1,5 @@ use crate::hardforks::bsc::BscHardfork; -use alloy_primitives::{BlockHash, U256, B256}; +use alloy_primitives::{BlockHash, B256, U256}; use reth_chainspec::{ make_genesis_header, BaseFeeParams, BaseFeeParamsKind, Chain, ChainSpec, Head, }; @@ -33,12 +33,12 @@ pub fn bsc_qanet() -> ChainSpec { // Dummy Head for BSC Qanet pub fn head() -> Head { - Head { - number: 1376256, + Head { + number: 1376256, hash: B256::from_str("0xd4d2ad3ff55bb663c0fcde91b99e5da1dad4aeb03b1605693650b2f2b0f2d88b") .unwrap(), difficulty: U256::from(2), total_difficulty: U256::from(2746312), - timestamp: 1756074108, + timestamp: 1756074108, } -} \ No newline at end of file +} diff --git a/src/chainspec/genesis_override.rs b/src/chainspec/genesis_override.rs index f054a665..e907cce0 100644 --- a/src/chainspec/genesis_override.rs +++ b/src/chainspec/genesis_override.rs @@ -1,6 +1,6 @@ -use std::sync::OnceLock; use alloy_primitives::B256; use eyre::Result; +use std::sync::OnceLock; /// Global storage for genesis hash override static GENESIS_HASH_OVERRIDE: OnceLock> = OnceLock::new(); @@ -9,20 +9,21 @@ static GENESIS_HASH_OVERRIDE: OnceLock> = OnceLock::new(); pub fn set_genesis_hash_override(hash_str: Option) -> Result<()> { let hash = match hash_str { Some(s) => { - let hash = s.parse::() - .map_err(|e| eyre::eyre!("Invalid genesis hash format: {}", e))?; + let hash = + s.parse::().map_err(|e| eyre::eyre!("Invalid genesis hash format: {}", e))?; Some(hash) } None => None, }; - - GENESIS_HASH_OVERRIDE.set(hash) + + GENESIS_HASH_OVERRIDE + .set(hash) .map_err(|_| eyre::eyre!("Genesis hash override already set"))?; - + if let Some(hash) = hash { tracing::info!("Genesis hash override set to: {:#x}", hash); } - + Ok(()) } @@ -60,13 +61,14 @@ mod tests { #[test] fn test_genesis_hash_parsing() { - let hash_str = "0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5".to_string(); + let hash_str = + "0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5".to_string(); set_genesis_hash_override(Some(hash_str)).expect("Should set genesis hash override"); - + let expected = "0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5" .parse::() .unwrap(); - + assert_eq!(get_genesis_hash_override(), Some(expected)); } @@ -77,11 +79,11 @@ mod tests { let test_hash = "0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5" .parse::() .unwrap(); - + // Test validation when no hash is set (should always pass) assert!(validate_genesis_hash(test_hash)); - + // Test validation when hash matches // (This test would need a way to reset global state to work properly) } -} \ No newline at end of file +} diff --git a/src/chainspec/local.rs b/src/chainspec/local.rs index e8fc11bf..4b596300 100644 --- a/src/chainspec/local.rs +++ b/src/chainspec/local.rs @@ -33,9 +33,9 @@ pub fn head() -> Head { #[cfg(test)] mod tests { use super::head; + use crate::chainspec::local::bsc_local; use alloy_primitives::hex; use reth_chainspec::{ForkHash, ForkId}; - use crate::chainspec::local::bsc_local; #[test] fn can_create_forkid() { diff --git a/src/chainspec/mod.rs b/src/chainspec/mod.rs index 8a922e07..edf3cf1c 100644 --- a/src/chainspec/mod.rs +++ b/src/chainspec/mod.rs @@ -5,20 +5,20 @@ use alloy_eips::eip7840::BlobParams; use alloy_genesis::Genesis; use alloy_primitives::{Address, B256, U256}; use reth_chainspec::{ - BaseFeeParams, ChainKind, ChainSpec, DepositContract, EthChainSpec, EthereumHardfork, EthereumHardforks, - ForkCondition, ForkFilter, ForkId, Hardforks, Head, NamedChain, + BaseFeeParams, ChainKind, ChainSpec, DepositContract, EthChainSpec, EthereumHardfork, + EthereumHardforks, ForkCondition, ForkFilter, ForkId, Hardforks, Head, NamedChain, }; use reth_discv4::NodeRecord; use reth_evm::eth::spec::EthExecutorSpec; use std::{fmt::Display, sync::Arc}; +pub mod bootnode_override; pub mod bsc; pub mod bsc_chapel; pub mod bsc_rialto; -pub mod parser; pub mod genesis_override; -pub mod bootnode_override; mod local; +pub mod parser; pub use bsc_chapel::bsc_testnet; @@ -63,7 +63,7 @@ impl EthChainSpec for BscChainSpec { if let Some(override_hash) = genesis_override::get_genesis_hash_override() { return override_hash; } - + self.inner.genesis_hash() } @@ -88,7 +88,7 @@ impl EthChainSpec for BscChainSpec { if bootnode_override::has_bootnode_override() { return bootnode_override::get_bootnode_override().clone(); } - + // Fall back to default bootnodes based on chain match self.inner.chain().kind() { ChainKind::Named(NamedChain::BinanceSmartChain) => { @@ -170,15 +170,9 @@ impl BscChainSpec { /// Get the head information for this chain spec pub fn head(&self) -> Head { let mut head = match self.inner.chain().kind() { - ChainKind::Named(NamedChain::BinanceSmartChain) => { - bsc::head() - } - ChainKind::Named(NamedChain::BinanceSmartChainTestnet) => { - bsc_chapel::head() - } - ChainKind::Id(bsc_rialto::RIALTO_CHAIN_ID) => { - bsc_rialto::head() - } + ChainKind::Named(NamedChain::BinanceSmartChain) => bsc::head(), + ChainKind::Named(NamedChain::BinanceSmartChainTestnet) => bsc_chapel::head(), + ChainKind::Id(bsc_rialto::RIALTO_CHAIN_ID) => bsc_rialto::head(), _ => local::head(), }; @@ -257,59 +251,95 @@ mod tests { fn test_genesis_hash_override_complete() { use alloy_primitives::B256; use std::str::FromStr; - + let chain_spec = BscChainSpec::from(bsc_testnet()); - + // Check if override is already set from other tests - let override_already_set = crate::chainspec::genesis_override::get_genesis_hash_override().is_some(); - + let override_already_set = + crate::chainspec::genesis_override::get_genesis_hash_override().is_some(); + if !override_already_set { // Test original behavior without override first let original_genesis_hash = chain_spec.genesis_hash(); let original_head = chain_spec.head(); - + // Set genesis hash override - let custom_genesis_hash = B256::from_str("0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5").unwrap(); - crate::chainspec::genesis_override::set_genesis_hash_override(Some("0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5".to_string())) - .expect("Should set genesis hash override"); - + let custom_genesis_hash = B256::from_str( + "0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5", + ) + .unwrap(); + crate::chainspec::genesis_override::set_genesis_hash_override(Some( + "0xb4844167d735617495363867c84affa9f4069bcdae48411ae3badbe1d227d3e5".to_string(), + )) + .expect("Should set genesis hash override"); + // Test that all methods now use the override let overridden_genesis_hash = chain_spec.genesis_hash(); - assert_eq!(overridden_genesis_hash, custom_genesis_hash, "genesis_hash() should return the override"); - + assert_eq!( + overridden_genesis_hash, custom_genesis_hash, + "genesis_hash() should return the override" + ); + let overridden_head = chain_spec.head(); - assert_eq!(overridden_head.hash, custom_genesis_hash, "head().hash should use the override"); - assert_eq!(overridden_head.number, original_head.number, "head().number should remain unchanged"); - assert_eq!(overridden_head.timestamp, original_head.timestamp, "head().timestamp should remain unchanged"); - + assert_eq!( + overridden_head.hash, custom_genesis_hash, + "head().hash should use the override" + ); + assert_eq!( + overridden_head.number, original_head.number, + "head().number should remain unchanged" + ); + assert_eq!( + overridden_head.timestamp, original_head.timestamp, + "head().timestamp should remain unchanged" + ); + // Test fork ID calculations with override let overridden_fork_id = chain_spec.fork_id(&overridden_head); let overridden_latest_fork_id = chain_spec.latest_fork_id(); - + // NOTE: Fork ID calculation in reth may not directly use the head hash or our genesis_hash() override - // because the inner chainspec doesn't know about our override. The key thing is that our + // because the inner chainspec doesn't know about our override. The key thing is that our // genesis_hash() and head() methods correctly return the override. - + // Verify that our methods are consistent with each other - assert_eq!(overridden_fork_id.hash, overridden_latest_fork_id.hash, "fork_id() and latest_fork_id() should have same hash"); - assert_eq!(overridden_fork_id.next, overridden_latest_fork_id.next, "fork_id() and latest_fork_id() should have same next"); - + assert_eq!( + overridden_fork_id.hash, overridden_latest_fork_id.hash, + "fork_id() and latest_fork_id() should have same hash" + ); + assert_eq!( + overridden_fork_id.next, overridden_latest_fork_id.next, + "fork_id() and latest_fork_id() should have same next" + ); + // Test validation function - assert!(crate::chainspec::genesis_override::validate_genesis_hash(custom_genesis_hash), "Custom genesis hash should validate"); - assert!(!crate::chainspec::genesis_override::validate_genesis_hash(original_genesis_hash), "Original genesis hash should not validate with override set"); + assert!( + crate::chainspec::genesis_override::validate_genesis_hash(custom_genesis_hash), + "Custom genesis hash should validate" + ); + assert!( + !crate::chainspec::genesis_override::validate_genesis_hash(original_genesis_hash), + "Original genesis hash should not validate with override set" + ); } else { // Override is already set from another test, just verify it's working - let current_override = crate::chainspec::genesis_override::get_genesis_hash_override().unwrap(); - + let current_override = + crate::chainspec::genesis_override::get_genesis_hash_override().unwrap(); + let genesis_hash = chain_spec.genesis_hash(); let head = chain_spec.head(); let fork_id = chain_spec.fork_id(&head); let latest_fork_id = chain_spec.latest_fork_id(); - - assert_eq!(genesis_hash, current_override, "genesis_hash() should match current override"); + + assert_eq!( + genesis_hash, current_override, + "genesis_hash() should match current override" + ); assert_eq!(head.hash, current_override, "head().hash should match current override"); - assert_eq!(fork_id.hash, latest_fork_id.hash, "fork_id() and latest_fork_id() should have same hash"); - + assert_eq!( + fork_id.hash, latest_fork_id.hash, + "fork_id() and latest_fork_id() should have same hash" + ); } } @@ -320,9 +350,15 @@ mod tests { let head = chain_spec.head(); let fork_id = chain_spec.fork_id(&head); let latest_fork_id = chain_spec.latest_fork_id(); - + // Test consistency - assert_eq!(fork_id.hash, latest_fork_id.hash, "fork_id and latest_fork_id should have same hash"); - assert_eq!(fork_id.next, latest_fork_id.next, "fork_id and latest_fork_id should have same next"); + assert_eq!( + fork_id.hash, latest_fork_id.hash, + "fork_id and latest_fork_id should have same hash" + ); + assert_eq!( + fork_id.next, latest_fork_id.next, + "fork_id and latest_fork_id should have same next" + ); } } diff --git a/src/consensus/eip4844/blob_fee.rs b/src/consensus/eip4844/blob_fee.rs index 489f2fe3..b5dc81c3 100644 --- a/src/consensus/eip4844/blob_fee.rs +++ b/src/consensus/eip4844/blob_fee.rs @@ -1,5 +1,5 @@ -use crate::hardforks::BscHardforks; use crate::chainspec::BscChainSpec; +use crate::hardforks::BscHardforks; use alloy_consensus::Header; use alloy_eips::eip4844; use alloy_eips::eip7691; @@ -13,37 +13,33 @@ pub const CANCUN_UPDATE_FRACTION: u64 = eip4844::BLOB_GASPRICE_UPDATE_FRACTION a pub fn calc_blob_fee(chain_spec: &BscChainSpec, header: &Header) -> u128 { let frac = get_update_fraction(chain_spec, header.timestamp); - + let excess_blob_gas = header.excess_blob_gas.unwrap_or(0); - eip4844::fake_exponential( - MIN_BLOB_GAS_PRICE, - u128::from(excess_blob_gas), - u128::from(frac) - ) + eip4844::fake_exponential(MIN_BLOB_GAS_PRICE, u128::from(excess_blob_gas), u128::from(frac)) } fn get_update_fraction(chain_spec: &BscChainSpec, timestamp: u64) -> u64 { use crate::hardforks::bsc::BscHardfork; - + if chain_spec.bsc_fork_activation(BscHardfork::Fermi).active_at_timestamp(timestamp) { return eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA as u64; } - + if chain_spec.bsc_fork_activation(BscHardfork::Maxwell).active_at_timestamp(timestamp) { return eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA as u64; } - + if chain_spec.bsc_fork_activation(BscHardfork::Lorentz).active_at_timestamp(timestamp) { return eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA as u64; } - + if reth_chainspec::EthereumHardforks::is_prague_active_at_timestamp(chain_spec, timestamp) { return eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA as u64; } - + if chain_spec.bsc_fork_activation(BscHardfork::Cancun).active_at_timestamp(timestamp) { return CANCUN_UPDATE_FRACTION; } - + panic!("calculating blob fee on unsupported fork") } diff --git a/src/consensus/eip4844/mod.rs b/src/consensus/eip4844/mod.rs index aef3f86e..2aa2c064 100644 --- a/src/consensus/eip4844/mod.rs +++ b/src/consensus/eip4844/mod.rs @@ -4,9 +4,7 @@ mod blob_fee; mod bep657; pub use blob_fee::{ - calc_blob_fee, - CANCUN_UPDATE_FRACTION, MIN_BLOB_GAS_PRICE, - BLOB_TX_BLOB_GAS_PER_BLOB, + calc_blob_fee, BLOB_TX_BLOB_GAS_PER_BLOB, CANCUN_UPDATE_FRACTION, MIN_BLOB_GAS_PRICE, }; pub use bep657::{ is_blob_eligible_block, next_block_excess_blob_gas_with_mendel, diff --git a/src/consensus/mod.rs b/src/consensus/mod.rs index 6a799c3c..b96b782d 100644 --- a/src/consensus/mod.rs +++ b/src/consensus/mod.rs @@ -1,5 +1,5 @@ use alloy_consensus::constants::ETH_TO_WEI; -use alloy_primitives::{Address, B256, address}; +use alloy_primitives::{address, Address, B256}; use reth_provider::ProviderError; pub const SYSTEM_ADDRESS: Address = address!("0xfffffffffffffffffffffffffffffffffffffffe"); diff --git a/src/consensus/parlia/bls_signer.rs b/src/consensus/parlia/bls_signer.rs index f2e2c364..92a5e4f1 100644 --- a/src/consensus/parlia/bls_signer.rs +++ b/src/consensus/parlia/bls_signer.rs @@ -1,10 +1,13 @@ -use std::{path::{Path, PathBuf}, sync::Arc}; +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; -use alloy_primitives::{hex, B256, FixedBytes}; +use alloy_primitives::{hex, FixedBytes, B256}; use once_cell::sync::OnceCell; -use zeroize::{Zeroize, Zeroizing}; use serde_json::Value as JsonValue; use std::fs; +use zeroize::{Zeroize, Zeroizing}; use super::vote::{VoteAddress, VoteData, VoteEnvelope, VoteSignature}; use blst::min_pk::SecretKey; @@ -42,12 +45,14 @@ pub struct BlsVoteSigner { impl BlsVoteSigner { pub fn new_from_bytes(bytes: [u8; 32]) -> Result { // Validate secret key by attempting to parse - SecretKey::from_bytes(&bytes).map_err(|e| BlsSignerError::InvalidSecret(format!("{e:?}")))?; + SecretKey::from_bytes(&bytes) + .map_err(|e| BlsSignerError::InvalidSecret(format!("{e:?}")))?; Ok(Self { sk_bytes: Zeroizing::new(bytes) }) } fn secret_key(&self) -> Result { - SecretKey::from_bytes(self.sk_bytes.as_slice()).map_err(|e| BlsSignerError::InvalidSecret(format!("{e:?}"))) + SecretKey::from_bytes(self.sk_bytes.as_slice()) + .map_err(|e| BlsSignerError::InvalidSecret(format!("{e:?}"))) } pub fn public_key(&self) -> Result { @@ -77,9 +82,7 @@ static GLOBAL_BLS_SIGNER: OnceCell> = OnceCell::new(); pub fn init_global_bls_signer_from_bytes(bytes: [u8; 32]) -> Result<(), BlsSignerError> { let signer = Arc::new(BlsVoteSigner::new_from_bytes(bytes)?); let vote_addr = signer.public_key()?; - GLOBAL_BLS_SIGNER - .set(signer) - .map_err(|_| BlsSignerError::AlreadyInitialized)?; + GLOBAL_BLS_SIGNER.set(signer).map_err(|_| BlsSignerError::AlreadyInitialized)?; tracing::info!( target: "bsc::bls", vote_address = %format!("0x{}", hex::encode(vote_addr)), @@ -91,29 +94,42 @@ pub fn init_global_bls_signer_from_bytes(bytes: [u8; 32]) -> Result<(), BlsSigne pub fn init_global_bls_signer_from_hex(hex_key: &str) -> Result<(), BlsSignerError> { let mut raw = hex::decode(hex_key.strip_prefix("0x").unwrap_or(hex_key)) .map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; - if raw.len() != 32 { return Err(BlsSignerError::InvalidSecret("BLS secret must be 32 bytes".into())); } + if raw.len() != 32 { + return Err(BlsSignerError::InvalidSecret("BLS secret must be 32 bytes".into())); + } let mut arr = [0u8; 32]; arr.copy_from_slice(&raw); raw.zeroize(); init_global_bls_signer_from_bytes(arr) } -pub fn init_global_bls_signer_from_keystore(path: &Path, password: &str) -> Result<(), BlsSignerError> { +pub fn init_global_bls_signer_from_keystore( + path: &Path, + password: &str, +) -> Result<(), BlsSignerError> { // If path is a directory (Prysm wallet), search keys/* for keystore(s) let target = if path.is_dir() { let mut keyfile: Option = None; let keys_dir = path.join("keys"); if keys_dir.is_dir() { - for entry in fs::read_dir(&keys_dir).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))? { + for entry in + fs::read_dir(&keys_dir).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))? + { let entry = entry.map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; let p = entry.path(); - if p.extension().and_then(|s| s.to_str()).map(|s| s.eq_ignore_ascii_case("json")).unwrap_or(false) { + if p.extension() + .and_then(|s| s.to_str()) + .map(|s| s.eq_ignore_ascii_case("json")) + .unwrap_or(false) + { keyfile = Some(p); break; } } } - keyfile.ok_or_else(|| BlsSignerError::InvalidSecret("No keystore JSON found under wallet/keys".into()))? + keyfile.ok_or_else(|| { + BlsSignerError::InvalidSecret("No keystore JSON found under wallet/keys".into()) + })? } else { path.to_path_buf() }; @@ -129,15 +145,25 @@ pub fn init_global_bls_signer_from_keystore(path: &Path, password: &str) -> Resu tracing::debug!("Reading BLS keystore password from file via file: prefix",); match fs::read_to_string(p) { Ok(s) => s.trim_end_matches(['\n', '\r']).to_string(), - Err(e) => return Err(BlsSignerError::InvalidSecret(format!("failed to read password file: {e}"))), + Err(e) => { + return Err(BlsSignerError::InvalidSecret(format!( + "failed to read password file: {e}" + ))) + } } } else { let p = Path::new(password); if p.is_file() { - tracing::warn!("Interpreting BLS keystore password as file path; prefer 'file:' prefix"); + tracing::warn!( + "Interpreting BLS keystore password as file path; prefer 'file:' prefix" + ); match fs::read_to_string(p) { Ok(s) => s.trim_end_matches(['\n', '\r']).to_string(), - Err(e) => return Err(BlsSignerError::InvalidSecret(format!("failed to read password file: {e}"))), + Err(e) => { + return Err(BlsSignerError::InvalidSecret(format!( + "failed to read password file: {e}" + ))) + } } } else { password.to_string() @@ -160,7 +186,9 @@ pub fn init_global_bls_signer_from_keystore(path: &Path, password: &str) -> Resu // Otherwise, try Ethereum V3 keystore let mut key_bytes = eth_keystore::decrypt_key(&target, &actual_password) .map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; - if key_bytes.len() != 32 { return Err(BlsSignerError::InvalidSecret("BLS secret must be 32 bytes".into())); } + if key_bytes.len() != 32 { + return Err(BlsSignerError::InvalidSecret("BLS secret must be 32 bytes".into())); + } let mut arr = [0u8; 32]; arr.copy_from_slice(&key_bytes); key_bytes.zeroize(); @@ -168,36 +196,72 @@ pub fn init_global_bls_signer_from_keystore(path: &Path, password: &str) -> Resu } fn decrypt_eip2335_keystore(path: &Path, password: &str) -> Result<[u8; 32], BlsSignerError> { - let contents = fs::read_to_string(path).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; - let v: JsonValue = serde_json::from_str(&contents).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; + let contents = + fs::read_to_string(path).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; + let v: JsonValue = serde_json::from_str(&contents) + .map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; - let version = v.get("version").and_then(|x| x.as_u64()).ok_or_else(|| BlsSignerError::InvalidSecret("missing version".into()))?; - if version != 4 { return Err(BlsSignerError::InvalidSecret("not EIP-2335 v4".into())); } + let version = v + .get("version") + .and_then(|x| x.as_u64()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing version".into()))?; + if version != 4 { + return Err(BlsSignerError::InvalidSecret("not EIP-2335 v4".into())); + } - let crypto = v.get("crypto").ok_or_else(|| BlsSignerError::InvalidSecret("missing crypto".into()))?; - let kdf = crypto.get("kdf").ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf".into()))?; - let kdf_fn = kdf.get("function").and_then(|x| x.as_str()).ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.function".into()))?; - let kdf_params = kdf.get("params").ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params".into()))?; + let crypto = + v.get("crypto").ok_or_else(|| BlsSignerError::InvalidSecret("missing crypto".into()))?; + let kdf = + crypto.get("kdf").ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf".into()))?; + let kdf_fn = kdf + .get("function") + .and_then(|x| x.as_str()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.function".into()))?; + let kdf_params = kdf + .get("params") + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params".into()))?; let dklen = kdf_params.get("dklen").and_then(|x| x.as_u64()).unwrap_or(32) as usize; - let salt_hex = kdf_params.get("salt").and_then(|x| x.as_str()).ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.salt".into()))?; + let salt_hex = kdf_params + .get("salt") + .and_then(|x| x.as_str()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.salt".into()))?; let mut salt = decode_hex_noprefix(salt_hex)?; // Derive key let mut dk = vec![0u8; dklen]; match kdf_fn.to_ascii_lowercase().as_str() { "scrypt" => { - let n = kdf_params.get("n").and_then(|x| x.as_u64()).ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.n".into()))?; - let r = kdf_params.get("r").and_then(|x| x.as_u64()).ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.r".into()))? as u32; - let p = kdf_params.get("p").and_then(|x| x.as_u64()).ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.p".into()))? as u32; + let n = kdf_params + .get("n") + .and_then(|x| x.as_u64()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.n".into()))?; + let r = kdf_params + .get("r") + .and_then(|x| x.as_u64()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.r".into()))? + as u32; + let p = kdf_params + .get("p") + .and_then(|x| x.as_u64()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.p".into()))? + as u32; // scrypt crate uses log2(N) - if n == 0 || (n & (n - 1)) != 0 { return Err(BlsSignerError::InvalidSecret("scrypt N must be power of two".into())); } + if n == 0 || (n & (n - 1)) != 0 { + return Err(BlsSignerError::InvalidSecret("scrypt N must be power of two".into())); + } // log2(N) for power-of-two N. Using trailing_zeros avoids magic constants like 64 (u64::BITS). let log_n: u8 = n.trailing_zeros() as u8; - let params = scrypt::Params::new(log_n, r, p, dklen).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; - scrypt::scrypt(password.as_bytes(), &salt, ¶ms, &mut dk).map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; + let params = scrypt::Params::new(log_n, r, p, dklen) + .map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; + scrypt::scrypt(password.as_bytes(), &salt, ¶ms, &mut dk) + .map_err(|e| BlsSignerError::InvalidSecret(e.to_string()))?; } "pbkdf2" => { - let c = kdf_params.get("c").and_then(|x| x.as_u64()).ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.c".into()))? as u32; + let c = kdf_params + .get("c") + .and_then(|x| x.as_u64()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing kdf.params.c".into()))? + as u32; use pbkdf2::pbkdf2_hmac; use sha2::Sha256; pbkdf2_hmac::(password.as_bytes(), &salt, c, &mut dk); @@ -208,26 +272,44 @@ fn decrypt_eip2335_keystore(path: &Path, password: &str) -> Result<[u8; 32], Bls salt.zeroize(); // Parse cipher params and ciphertext - let cipher = crypto.get("cipher").ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher".into()))?; + let cipher = crypto + .get("cipher") + .ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher".into()))?; let cipher_fn = cipher.get("function").and_then(|x| x.as_str()).unwrap_or(""); - let cipher_params = cipher.get("params").ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher.params".into()))?; - let iv_hex = cipher_params.get("iv").and_then(|x| x.as_str()).ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher.params.iv".into()))?; + let cipher_params = cipher + .get("params") + .ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher.params".into()))?; + let iv_hex = cipher_params + .get("iv") + .and_then(|x| x.as_str()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher.params.iv".into()))?; let mut iv = decode_hex_noprefix(iv_hex)?; - if iv.len() != 16 { return Err(BlsSignerError::InvalidSecret("iv must be 16 bytes".into())); } - let ct_hex = cipher.get("message").and_then(|x| x.as_str()).ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher.message".into()))?; + if iv.len() != 16 { + return Err(BlsSignerError::InvalidSecret("iv must be 16 bytes".into())); + } + let ct_hex = cipher + .get("message") + .and_then(|x| x.as_str()) + .ok_or_else(|| BlsSignerError::InvalidSecret("missing cipher.message".into()))?; let mut ct = decode_hex_noprefix(ct_hex)?; // Verify checksum first: sha256(derived_key[16..32] || ciphertext) - let checksum = crypto.get("checksum").ok_or_else(|| BlsSignerError::InvalidSecret("missing checksum".into()))?; + let checksum = crypto + .get("checksum") + .ok_or_else(|| BlsSignerError::InvalidSecret("missing checksum".into()))?; let checksum_msg = checksum.get("message").and_then(|x| x.as_str()).unwrap_or(""); - use sha2::{Sha256, Digest}; - if dklen < 32 { return Err(BlsSignerError::InvalidSecret("dklen too small".into())); } + use sha2::{Digest, Sha256}; + if dklen < 32 { + return Err(BlsSignerError::InvalidSecret("dklen too small".into())); + } let mut hasher = Sha256::new(); hasher.update(&dk[16..32]); hasher.update(&ct); let calc = hasher.finalize(); let calc_hex = hex::encode(calc); - if !eq_hex_noprefix(&calc_hex, checksum_msg) { return Err(BlsSignerError::InvalidSecret("checksum mismatch".into())); } + if !eq_hex_noprefix(&calc_hex, checksum_msg) { + return Err(BlsSignerError::InvalidSecret("checksum mismatch".into())); + } // Decrypt AES-CTR after checksum validation use aes::{Aes128, Aes256}; @@ -246,7 +328,9 @@ fn decrypt_eip2335_keystore(path: &Path, password: &str) -> Result<[u8; 32], Bls return Err(BlsSignerError::InvalidSecret("unsupported cipher".into())); } - if ct.len() != 32 { return Err(BlsSignerError::InvalidSecret("decrypted secret wrong length".into())); } + if ct.len() != 32 { + return Err(BlsSignerError::InvalidSecret("decrypted secret wrong length".into())); + } let mut out = [0u8; 32]; out.copy_from_slice(&ct); @@ -267,9 +351,13 @@ fn decode_hex_noprefix(s: &str) -> Result, BlsSignerError> { hex::decode(ss).map_err(|e| BlsSignerError::InvalidSecret(e.to_string())) } -pub fn get_global_bls_signer() -> Option<&'static Arc> { GLOBAL_BLS_SIGNER.get() } +pub fn get_global_bls_signer() -> Option<&'static Arc> { + GLOBAL_BLS_SIGNER.get() +} -pub fn is_bls_signer_initialized() -> bool { GLOBAL_BLS_SIGNER.get().is_some() } +pub fn is_bls_signer_initialized() -> bool { + GLOBAL_BLS_SIGNER.get().is_some() +} pub fn global_bls_public_key() -> Result { get_global_bls_signer().ok_or(BlsSignerError::NotInitialized)?.public_key() @@ -287,7 +375,9 @@ pub fn init_from_env_if_present() { let keystore_password = std::env::var("BSC_BLS_KEYSTORE_PASSWORD").ok(); let bls_hex = std::env::var("BSC_BLS_PRIVATE_KEY").ok(); - if is_bls_signer_initialized() { return; } + if is_bls_signer_initialized() { + return; + } if let (Some(path), Some(pass)) = (keystore_path, keystore_password) { match init_global_bls_signer_from_keystore(Path::new(&path), &pass) { @@ -299,7 +389,9 @@ pub fn init_from_env_if_present() { if let Some(hex_key) = bls_hex { match init_global_bls_signer_from_hex(&hex_key) { - Ok(()) => tracing::warn!("Initialized BLS signer from hex (not recommended for production)"), + Ok(()) => { + tracing::warn!("Initialized BLS signer from hex (not recommended for production)") + } Err(e) => tracing::warn!("Failed to init BLS signer from hex: {}", e), } } @@ -308,7 +400,10 @@ pub fn init_from_env_if_present() { #[cfg(test)] mod tests { use super::*; - use blst::{min_pk::{PublicKey, Signature}, BLST_ERROR}; + use blst::{ + min_pk::{PublicKey, Signature}, + BLST_ERROR, + }; #[test] fn bls_sign_and_verify_single_key() { diff --git a/src/consensus/parlia/constants.rs b/src/consensus/parlia/constants.rs index 26e71553..98c0518b 100644 --- a/src/consensus/parlia/constants.rs +++ b/src/consensus/parlia/constants.rs @@ -16,7 +16,7 @@ pub const TURN_LENGTH_SIZE: usize = 1; /// Difficulty for in-turn block (when it's the proposer's turn) pub const DIFF_INTURN: U256 = U256::from_limbs([2, 0, 0, 0]); /// Difficulty for out-of-turn block (when it's not the proposer's turn) -pub const DIFF_NOTURN: U256 = U256::from_limbs([1, 0, 0, 0]); +pub const DIFF_NOTURN: U256 = U256::from_limbs([1, 0, 0, 0]); pub const COLLECT_ADDITIONAL_VOTES_REWARD_RATIO: usize = 100; @@ -42,7 +42,9 @@ pub const DEFAULT_MIN_GAS_TIP: u128 = 50_000_000; // 0.05 Gwei pub const FF_REWARD_DISTRIBUTION_INTERVAL: u64 = 200; // EmptyWithdrawalsHash is the known hash of the empty withdrawal set. -pub const EMPTY_WITHDRAWALS_HASH: B256 = b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); +pub const EMPTY_WITHDRAWALS_HASH: B256 = + b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); // EmptyRequestsHash is the known hash of an empty request set, sha256(""). -pub const EMPTY_REQUESTS_HASH: B256 = b256!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); \ No newline at end of file +pub const EMPTY_REQUESTS_HASH: B256 = + b256!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); diff --git a/src/consensus/parlia/db.rs b/src/consensus/parlia/db.rs index 1b9ecfa2..8e989952 100644 --- a/src/consensus/parlia/db.rs +++ b/src/consensus/parlia/db.rs @@ -1,5 +1,5 @@ -use reth_db::table::Table; use alloy_primitives::BlockHash; +use reth_db::table::Table; /// Table: epoch boundary block number (u64) -> compressed snapshot bytes. #[derive(Debug)] @@ -11,7 +11,7 @@ impl Table for ParliaSnapshots { type Key = u64; /// Raw compressed bytes produced by `Snapshot::compress()`. type Value = reth_db::models::ParliaSnapshotBlob; -} +} /// Table: epoch boundary block hash (BlockHash) -> compressed snapshot bytes. #[derive(Debug)] @@ -23,4 +23,4 @@ impl Table for ParliaSnapshotsByHash { type Key = BlockHash; /// Raw compressed bytes produced by `Snapshot::compress()`. type Value = reth_db::models::ParliaSnapshotBlob; -} \ No newline at end of file +} diff --git a/src/consensus/parlia/error.rs b/src/consensus/parlia/error.rs index 3ba11eda..91be04a9 100644 --- a/src/consensus/parlia/error.rs +++ b/src/consensus/parlia/error.rs @@ -2,7 +2,6 @@ use alloy_primitives::{BlockHash, BlockNumber}; use crate::consensus::parlia::VoteAddress; - /// Parlia consensus error. #[derive(thiserror::Error, Debug, PartialEq, Eq, Clone)] pub enum ParliaConsensusError { @@ -69,9 +68,7 @@ pub enum ParliaConsensusError { /// Error when header extra attestation is invalid #[error("fetch vote error")] - FetchVoteError { - address: VoteAddress, - }, + FetchVoteError { address: VoteAddress }, /// Error when aggregate signature failed #[error("aggregate signature failed")] @@ -79,14 +76,9 @@ pub enum ParliaConsensusError { /// Error when invalid attestation vote count #[error("invalid attestation vote count")] - InvalidAttestationVoteCount { - got: u32, - expected: u32, - }, + InvalidAttestationVoteCount { got: u32, expected: u32 }, /// Error when turn length is not found #[error("turn length not found")] - TurnLengthNotFound { - block_hash: BlockHash, - }, -} \ No newline at end of file + TurnLengthNotFound { block_hash: BlockHash }, +} diff --git a/src/consensus/parlia/forkchoice_rule.rs b/src/consensus/parlia/forkchoice_rule.rs index dd6e597f..1d6a53f0 100644 --- a/src/consensus/parlia/forkchoice_rule.rs +++ b/src/consensus/parlia/forkchoice_rule.rs @@ -1,7 +1,7 @@ use crate::{chainspec::BscChainSpec, hardforks::BscHardforks}; use alloy_consensus::Header; use alloy_primitives::U256; -use std::{sync::Arc, cmp::Ordering}; +use std::{cmp::Ordering, sync::Arc}; /// Header with additional fork choice metadata. /// @@ -20,11 +20,7 @@ pub struct HeaderForForkchoice<'a> { impl<'a> HeaderForForkchoice<'a> { /// Creates a new `HeaderForForkchoice` instance. pub fn new(header: &'a Header, td: Option, justified_num: u64) -> Self { - Self { - header, - td, - justified_num, - } + Self { header, td, justified_num } } } @@ -77,7 +73,7 @@ impl BscForkChoiceRule { // Fallback to TD-based comparison let result = self.head_choice_with_td(incoming, current)?; - + tracing::info!( target: "bsc::forkchoice", need_reorg = result, @@ -90,7 +86,7 @@ impl BscForkChoiceRule { method = "total_difficulty", "Fork choice decision made by total difficulty comparison" ); - + Ok(result) } @@ -104,8 +100,9 @@ impl BscForkChoiceRule { current: &HeaderForForkchoice, ) -> Option { // Check if Plato fork is active for either header - if !self.spec.as_ref().is_plato_active_at_block(incoming.header.number) && - !self.spec.as_ref().is_plato_active_at_block(current.header.number) { + if !self.spec.as_ref().is_plato_active_at_block(incoming.header.number) + && !self.spec.as_ref().is_plato_active_at_block(current.header.number) + { return None; } @@ -118,7 +115,9 @@ impl BscForkChoiceRule { // If justified numbers differ, use fast finality rule if incoming.justified_num != current.justified_num { - if incoming.justified_num > current.justified_num && incoming.header.number <= current.header.number { + if incoming.justified_num > current.justified_num + && incoming.header.number <= current.header.number + { tracing::info!( target: "bsc::forkchoice", from_height = current.header.number, @@ -145,12 +144,16 @@ impl BscForkChoiceRule { incoming: &HeaderForForkchoice, current: &HeaderForForkchoice, ) -> Result { - let current_td = current.td.ok_or( - crate::consensus::ParliaConsensusErr::UnknownTotalDifficulty(current.header.hash_slow(), current.header.number) - )?; - let incoming_td = incoming.td.ok_or( - crate::consensus::ParliaConsensusErr::UnknownTotalDifficulty(incoming.header.hash_slow(), incoming.header.number) - )?; + let current_td = + current.td.ok_or(crate::consensus::ParliaConsensusErr::UnknownTotalDifficulty( + current.header.hash_slow(), + current.header.number, + ))?; + let incoming_td = + incoming.td.ok_or(crate::consensus::ParliaConsensusErr::UnknownTotalDifficulty( + incoming.header.hash_slow(), + incoming.header.number, + ))?; tracing::debug!( target: "bsc::forkchoice", @@ -199,7 +202,9 @@ impl BscForkChoiceRule { mod tests { use super::*; use crate::chainspec::{bsc::bsc_mainnet, bsc_rialto::bsc_qanet}; - use crate::consensus::parlia::{Snapshot, VoteData, VoteAttestation, EXTRA_VANITY_LEN, EXTRA_SEAL_LEN}; + use crate::consensus::parlia::{ + Snapshot, VoteAttestation, VoteData, EXTRA_SEAL_LEN, EXTRA_VANITY_LEN, + }; use alloy_consensus::Header; use alloy_primitives::{B256, U256}; @@ -219,11 +224,7 @@ mod tests { let mut extra = vec![0u8; EXTRA_VANITY_LEN]; extra.extend_from_slice(alloy_rlp::encode(&att).as_ref()); extra.extend_from_slice(&[0u8; EXTRA_SEAL_LEN]); - Header { - number, - extra_data: alloy_primitives::Bytes::from(extra), - ..Default::default() - } + Header { number, extra_data: alloy_primitives::Bytes::from(extra), ..Default::default() } } #[test] @@ -233,19 +234,19 @@ mod tests { let test_cases = [ // ((current_number, current_td), (new_number, new_td), should_reorg) - ((1, 2), (2, 4), true), // Higher TD wins - ((1, 2), (2, 1), false), // Lower TD loses - ((1, 2), (2, 2), false), // Same TD, higher number loses (current stays) - ((2, 2), (1, 2), true), // Same TD, lower number wins + ((1, 2), (2, 4), true), // Higher TD wins + ((1, 2), (2, 1), false), // Lower TD loses + ((1, 2), (2, 2), false), // Same TD, higher number loses (current stays) + ((2, 2), (1, 2), true), // Same TD, lower number wins ]; for ((curr_number, curr_td), (new_number, new_td), should_reorg) in test_cases { let curr_header = Header { number: curr_number, ..Default::default() }; let new_header = Header { number: new_number, ..Default::default() }; - + let current = HeaderForForkchoice::new(&curr_header, Some(U256::from(curr_td)), 0); let incoming = HeaderForForkchoice::new(&new_header, Some(U256::from(new_td)), 0); - + let result = rule.is_need_reorg(&incoming, ¤t).unwrap(); assert_eq!( result, should_reorg, @@ -263,9 +264,9 @@ mod tests { // Setup snapshot provider for fast finality tests if crate::shared::get_snapshot_provider().is_none() { // Create a simple in-memory snapshot provider for tests + use crate::consensus::parlia::SnapshotProvider; use std::collections::HashMap as StdHashMap; use std::sync::RwLock; - use crate::consensus::parlia::SnapshotProvider; #[derive(Debug)] struct TestSnapProvider { @@ -293,7 +294,7 @@ mod tests { } let sp = Arc::new(TestSnapProvider::new()); - + // Insert snapshots with vote data let test_cases = [ // (number, source_num, target_num) @@ -304,7 +305,7 @@ mod tests { (30, 28, 29), (31, 27, 28), ]; - + for (number, source_num, target_num) in test_cases { let header = header_with_attestation(number, source_num, target_num); let snapshot = Snapshot { @@ -320,26 +321,33 @@ mod tests { }; sp.insert_snap(snapshot); } - + let _ = crate::shared::set_snapshot_provider(sp); } let test_scenarios = [ - // ((current_number, current_td, current_source, current_target), + // ((current_number, current_td, current_source, current_target), // (incoming_number, incoming_td, incoming_source, incoming_target), should_reorg) - ((10, 20, 8, 9), (11, 22, 9, 10), true), // Higher justified number + ((10, 20, 8, 9), (11, 22, 9, 10), true), // Higher justified number ((20, 40, 18, 19), (21, 40, 18, 19), false), // Equal justified, equal TD ((20, 40, 18, 19), (21, 42, 18, 19), true), // Equal justified, higher TD ((30, 60, 28, 29), (31, 62, 27, 28), false), // Lower justified, higher TD ]; - for ((curr_num, curr_td, curr_src, curr_tgt), (inc_num, inc_td, inc_src, inc_tgt), should_reorg) in test_scenarios { + for ( + (curr_num, curr_td, curr_src, curr_tgt), + (inc_num, inc_td, inc_src, inc_tgt), + should_reorg, + ) in test_scenarios + { let current_header = header_with_attestation(curr_num, curr_src, curr_tgt); let incoming_header = header_with_attestation(inc_num, inc_src, inc_tgt); - - let current = HeaderForForkchoice::new(¤t_header, Some(U256::from(curr_td)), curr_tgt); - let incoming = HeaderForForkchoice::new(&incoming_header, Some(U256::from(inc_td)), inc_tgt); - + + let current = + HeaderForForkchoice::new(¤t_header, Some(U256::from(curr_td)), curr_tgt); + let incoming = + HeaderForForkchoice::new(&incoming_header, Some(U256::from(inc_td)), inc_tgt); + let result = rule.is_need_reorg(&incoming, ¤t).unwrap(); assert_eq!( result, should_reorg, @@ -348,4 +356,4 @@ mod tests { ); } } -} \ No newline at end of file +} diff --git a/src/consensus/parlia/mod.rs b/src/consensus/parlia/mod.rs index 7e51cc36..5169dbbe 100644 --- a/src/consensus/parlia/mod.rs +++ b/src/consensus/parlia/mod.rs @@ -1,29 +1,31 @@ -pub mod vote; -pub mod snapshot; -pub mod provider; -pub mod constants; -pub mod vote_pool; +pub mod bls_signer; pub mod consensus; -pub mod util; -pub mod error; -pub mod validation; +pub mod constants; pub mod db; -pub mod go_rng; -pub mod ramanujan_fork; -pub mod bls_signer; +pub mod error; pub mod forkchoice_rule; pub mod block_stats; pub mod malicious_vote_monitor; +pub mod go_rng; +pub mod provider; +pub mod ramanujan_fork; +pub mod snapshot; +pub mod util; +pub mod validation; +pub mod vote; +pub mod vote_pool; -#[cfg(test)] -mod tests; +#[cfg(test)] +mod tests; -pub use snapshot::{Snapshot, ValidatorInfo, CHECKPOINT_INTERVAL}; -pub use vote::{VoteAddress, VoteAttestation, VoteData, VoteEnvelope, VoteSignature, ValidatorsBitSet}; +pub use consensus::Parlia; pub use constants::*; pub use error::ParliaConsensusError; -pub use util::hash_with_chain_id; +pub use forkchoice_rule::{BscForkChoiceRule, HeaderForForkchoice}; pub use provider::SnapshotProvider; +pub use snapshot::{Snapshot, ValidatorInfo, CHECKPOINT_INTERVAL}; +pub use util::hash_with_chain_id; +pub use vote::{ + ValidatorsBitSet, VoteAddress, VoteAttestation, VoteData, VoteEnvelope, VoteSignature, +}; pub use vote_pool as votes; -pub use consensus::Parlia; -pub use forkchoice_rule::{BscForkChoiceRule, HeaderForForkchoice}; diff --git a/src/consensus/parlia/provider.rs b/src/consensus/parlia/provider.rs index 85cf6758..644f8b57 100644 --- a/src/consensus/parlia/provider.rs +++ b/src/consensus/parlia/provider.rs @@ -5,11 +5,11 @@ use std::sync::Arc; use crate::chainspec::BscChainSpec; -use crate::consensus::parlia::{CHECKPOINT_INTERVAL, Parlia, VoteAddress}; +use crate::consensus::parlia::{Parlia, VoteAddress, CHECKPOINT_INTERVAL}; use crate::node::evm::error::{BscBlockExecutionError, BscBlockValidationError}; use crate::node::evm::util::{get_cannonical_header_from_cache, get_header_by_hash_from_cache}; -use alloy_primitives::{Address}; -use alloy_primitives::{BlockHash}; +use alloy_primitives::Address; +use alloy_primitives::BlockHash; /// Validator information extracted from header #[derive(Debug, Clone)] @@ -18,11 +18,10 @@ pub struct ValidatorsInfo { pub vote_addrs: Option>, } - -use reth_db::{Database, DatabaseError}; -use reth_db::table::{Compress, Decompress}; use reth_db::models::ParliaSnapshotBlob; +use reth_db::table::{Compress, Decompress}; use reth_db::transaction::{DbTx, DbTxMut}; +use reth_db::{Database, DatabaseError}; use schnellru::{ByLength, LruMap}; pub trait SnapshotProvider: Send + Sync { @@ -54,25 +53,14 @@ pub struct EnhancedDbSnapshotProvider { impl DbSnapshotProvider { pub fn new(db: DB, capacity: usize) -> Self { - Self { - db, - cache_by_hash: RwLock::new(LruMap::new(ByLength::new(capacity as u32))), - } + Self { db, cache_by_hash: RwLock::new(LruMap::new(ByLength::new(capacity as u32))) } } } impl EnhancedDbSnapshotProvider { - pub fn new( - db: DB, - capacity: usize, - chain_spec: Arc, - ) -> Self { + pub fn new(db: DB, capacity: usize, chain_spec: Arc) -> Self { let parlia = Arc::new(Parlia::new(chain_spec.clone(), 200)); - Self { - base: DbSnapshotProvider::new(db, capacity), - chain_spec, - parlia, - } + Self { base: DbSnapshotProvider::new(db, capacity), chain_spec, parlia } } } @@ -96,10 +84,16 @@ impl Clone for EnhancedDbSnapshotProvider { impl DbSnapshotProvider { fn query_db_by_hash(&self, block_hash: &BlockHash) -> Option { let tx = self.db.tx().ok()?; - if let Ok(Some(raw_blob)) = tx.get::(*block_hash) { + if let Ok(Some(raw_blob)) = + tx.get::(*block_hash) + { let raw = &raw_blob.0; if let Ok(decoded) = Snapshot::decompress(raw) { - tracing::debug!("Succeed to query snapshot from db, block_number: {}, block_hash: {}", decoded.block_number, decoded.block_hash); + tracing::debug!( + "Succeed to query snapshot from db, block_number: {}, block_hash: {}", + decoded.block_number, + decoded.block_hash + ); return Some(decoded); } } @@ -108,9 +102,16 @@ impl DbSnapshotProvider { fn persist_to_db(&self, snap: &Snapshot) -> Result<(), DatabaseError> { let tx = self.db.tx_mut()?; - tx.put::(snap.block_hash, ParliaSnapshotBlob(snap.clone().compress()))?; + tx.put::( + snap.block_hash, + ParliaSnapshotBlob(snap.clone().compress()), + )?; tx.commit()?; - tracing::debug!("Succeed to insert snapshot to db, block_number: {}, block_hash: {}", snap.block_number, snap.block_hash); + tracing::debug!( + "Succeed to insert snapshot to db, block_number: {}, block_hash: {}", + snap.block_number, + snap.block_hash + ); Ok(()) } @@ -123,7 +124,8 @@ impl DbSnapshotProvider { impl SnapshotProvider for DbSnapshotProvider { fn snapshot_by_hash(&self, block_hash: &BlockHash) -> Option { - { // fast path: cache + { + // fast path: cache let mut guard = self.cache_by_hash.write(); if let Some(snap) = guard.get(block_hash) { return Some(snap.clone()); @@ -141,9 +143,13 @@ impl SnapshotProvider for DbSnapshotProvider { match self.persist_to_db(&snapshot) { Ok(()) => { tracing::debug!("Persisted snapshot for block {} to DB", snapshot.block_number); - }, + } Err(e) => { - tracing::error!("Failed to persist snapshot for block {} to DB: {:?}", snapshot.block_number, e); + tracing::error!( + "Failed to persist snapshot for block {} to DB: {:?}", + snapshot.block_number, + e + ); } } } @@ -151,8 +157,7 @@ impl SnapshotProvider for DbSnapshotProvider { } // Simplified version based on reth-bsc-trail's approach - much faster and simpler -impl SnapshotProvider for EnhancedDbSnapshotProvider -{ +impl SnapshotProvider for EnhancedDbSnapshotProvider { // query snapshot by hash, note that it will try to rebuild snapshot if not found. fn snapshot_by_hash(&self, block_hash: &BlockHash) -> Option { // query snapshot from cache or db @@ -162,13 +167,16 @@ impl SnapshotProvider for EnhancedDbSnapshotProvider if target_header.number == 0 { return self.init_genesis_snapshot(&target_header); } - let snap= self.try_rebuild(&target_header); + let snap = self.try_rebuild(&target_header); if let Some(s) = snap.as_ref() { self.base.insert(s.clone()); } snap } else { - tracing::warn!("Failed to query snapshot by hash due to not found header, block_hash: {}", block_hash); + tracing::warn!( + "Failed to query snapshot by hash due to not found header, block_hash: {}", + block_hash + ); None } } @@ -180,16 +188,17 @@ impl SnapshotProvider for EnhancedDbSnapshotProvider impl EnhancedDbSnapshotProvider { fn init_genesis_snapshot(&self, genesis_header: &Header) -> Option { - let ValidatorsInfo { consensus_addrs, vote_addrs } = - self.parlia.parse_validators_from_header( - genesis_header, - self.parlia.epoch) - .map_err(|err| { - tracing::error!("Failed to parse validators from genesis header: {:?}", err); - BscBlockExecutionError::Validation(BscBlockValidationError::ParliaConsensusError { error: err.into() }) + let ValidatorsInfo { consensus_addrs, vote_addrs } = self + .parlia + .parse_validators_from_header(genesis_header, self.parlia.epoch) + .map_err(|err| { + tracing::error!("Failed to parse validators from genesis header: {:?}", err); + BscBlockExecutionError::Validation(BscBlockValidationError::ParliaConsensusError { + error: err.into(), }) - .ok()?; - + }) + .ok()?; + let genesis_snapshot = Snapshot::new( consensus_addrs.clone(), 0, @@ -197,23 +206,28 @@ impl EnhancedDbSnapshotProvider { self.parlia.epoch, vote_addrs.clone(), ); - - tracing::info!("Genesis snapshot initialized: block=0, validators={}", - genesis_snapshot.validators.len()); - + + tracing::info!( + "Genesis snapshot initialized: block=0, validators={}", + genesis_snapshot.validators.len() + ); + self.base.insert(genesis_snapshot.clone()); Some(genesis_snapshot) } fn try_rebuild(&self, target_header: &Header) -> Option { let mut rebuild_block_hashes = Vec::new(); - let base_snapshot = { + let base_snapshot = { let mut parent_block_hash = target_header.parent_hash; rebuild_block_hashes.push(target_header.hash_slow()); loop { let parent_header = get_header_by_hash_from_cache(&parent_block_hash); if parent_header.is_none() { - tracing::warn!("Failed to query snapshot by hash due to not found header, block_hash: {}", parent_block_hash); + tracing::warn!( + "Failed to query snapshot by hash due to not found header, block_hash: {}", + parent_block_hash + ); break None; } if parent_header.clone().unwrap().number == 0 { @@ -223,7 +237,10 @@ impl EnhancedDbSnapshotProvider { break Some(snap); } rebuild_block_hashes.push(parent_block_hash); - tracing::trace!("Succeed to walk to parent block, parent_block_number: {}", parent_header.clone().unwrap().number); + tracing::trace!( + "Succeed to walk to parent block, parent_block_number: {}", + parent_header.clone().unwrap().number + ); parent_block_hash = parent_header.clone().unwrap().parent_hash; } }; @@ -231,15 +248,22 @@ impl EnhancedDbSnapshotProvider { tracing::warn!("Failed to rebuild snapshot due to not found base snapshot"); return None; } - tracing::debug!("try rebuild snapshot, from_block: {}, to_block: {}, rebuild_block_len: {:?}", - base_snapshot.clone().unwrap().block_number, target_header.number, rebuild_block_hashes.len()); + tracing::debug!( + "try rebuild snapshot, from_block: {}, to_block: {}, rebuild_block_len: {:?}", + base_snapshot.clone().unwrap().block_number, + target_header.number, + rebuild_block_hashes.len() + ); rebuild_block_hashes.reverse(); let mut working_snapshot = base_snapshot.clone().unwrap(); for block_hash in rebuild_block_hashes { let apply_header = get_header_by_hash_from_cache(&block_hash); if apply_header.is_none() { - tracing::warn!("Failed to query snapshot by hash due to not found header, block_hash: {}", block_hash); + tracing::warn!( + "Failed to query snapshot by hash due to not found header, block_hash: {}", + block_hash + ); return None; } let header = apply_header.unwrap(); @@ -247,7 +271,7 @@ impl EnhancedDbSnapshotProvider { let miner_check_len = working_snapshot.miner_history_check_len(); let is_epoch_boundary = header.number > 0 && epoch_remainder == miner_check_len; let mut turn_length = None; - + let validators_info = if is_epoch_boundary { let checkpoint_block_number = header.number - miner_check_len; tracing::debug!("Updating validator set at epoch boundary, checkpoint_block: {}, current_block: {}", @@ -291,36 +315,39 @@ impl EnhancedDbSnapshotProvider { }).ok()?; // Apply header to snapshot - working_snapshot = match working_snapshot.apply( - header.beneficiary, - &header, - new_validators, - vote_addrs, - attestation, - turn_length, - &*self.chain_spec, - ) { - Some(snap) => { - tracing::trace!( + working_snapshot = + match working_snapshot.apply( + header.beneficiary, + &header, + new_validators, + vote_addrs, + attestation, + turn_length, + &*self.chain_spec, + ) { + Some(snap) => { + tracing::trace!( "Successfully applied header: block_number={}, epoch_num={}, validators={}", snap.block_number, snap.epoch_num, snap.validators.len() ); - // Cache intermediate snapshots in memory to avoid repeated long rebuilds - self.base.insert_cache_only(&snap); - snap - }, - None => { - tracing::warn!("Failed to apply header {} to snapshot", header.number); - return None; - } - }; + // Cache intermediate snapshots in memory to avoid repeated long rebuilds + self.base.insert_cache_only(&snap); + snap + } + None => { + tracing::warn!("Failed to apply header {} to snapshot", header.number); + return None; + } + }; // Persist at checkpoint boundaries to DB; intermediate snapshots are cached in-memory only. - if working_snapshot.block_number.is_multiple_of(crate::consensus::parlia::snapshot::CHECKPOINT_INTERVAL) { + if working_snapshot + .block_number + .is_multiple_of(crate::consensus::parlia::snapshot::CHECKPOINT_INTERVAL) + { self.base.persist_to_db(&working_snapshot).ok()?; } } Some(working_snapshot) } - } diff --git a/src/consensus/parlia/ramanujan_fork.rs b/src/consensus/parlia/ramanujan_fork.rs index c77ab27b..acf38b75 100644 --- a/src/consensus/parlia/ramanujan_fork.rs +++ b/src/consensus/parlia/ramanujan_fork.rs @@ -1,25 +1,34 @@ -use alloy_consensus::Header; -use rand::Rng; -use crate::consensus::parlia::{Snapshot, FIXED_BACKOFF_TIME_BEFORE_FORK_MILLIS, WIGGLE_TIME_BEFORE_FORK_MILLIS, MILLISECONDS_UNIT}; -use crate::consensus::parlia::util::calculate_millisecond_timestamp; use crate::consensus::parlia::consensus::Parlia; use crate::consensus::parlia::constants::DIFF_NOTURN; +use crate::consensus::parlia::util::calculate_millisecond_timestamp; +use crate::consensus::parlia::{ + Snapshot, FIXED_BACKOFF_TIME_BEFORE_FORK_MILLIS, MILLISECONDS_UNIT, + WIGGLE_TIME_BEFORE_FORK_MILLIS, +}; use crate::hardforks::BscHardforks; -use reth_chainspec::EthChainSpec; use crate::node::evm::error::{BscBlockExecutionError, BscBlockValidationError}; +use alloy_consensus::Header; +use rand::Rng; +use reth_chainspec::EthChainSpec; use reth_evm::execute::BlockExecutionError; -impl Parlia -where ChainSpec: EthChainSpec + BscHardforks + 'static, +impl Parlia +where + ChainSpec: EthChainSpec + BscHardforks + 'static, { /// Calculate block time for Ramanujan fork, return in milliseconds. - pub fn block_time_for_ramanujan_fork(&self, snap: &Snapshot, parent: &Header, header: &Header) -> u64 { + pub fn block_time_for_ramanujan_fork( + &self, + snap: &Snapshot, + parent: &Header, + header: &Header, + ) -> u64 { let parent_ts = calculate_millisecond_timestamp(parent); let mut new_block_ts = parent_ts + snap.block_interval; if self.spec.is_ramanujan_active_at_block(header.number) { new_block_ts += self.back_off_time(snap, parent, header); } - + let now = self.present_millis_timestamp(); if new_block_ts < now { // Just to make the millisecond part of the time look more aligned. @@ -27,7 +36,7 @@ where ChainSpec: EthChainSpec + BscHardforks + 'static, } new_block_ts } - + /// Calculate delay for Ramanujan fork, return in milliseconds. pub fn delay_for_ramanujan_fork(&self, parent_snap: &Snapshot, header: &Header) -> u64 { let present_timestamp = self.present_millis_timestamp(); @@ -51,19 +60,25 @@ where ChainSpec: EthChainSpec + BscHardforks + 'static, // It's not our turn explicitly to sign, delay it a bit if header.difficulty == DIFF_NOTURN { - let wiggle = (parent_snap.validators.len() / 2 + 1) as u64 * WIGGLE_TIME_BEFORE_FORK_MILLIS; + let wiggle = + (parent_snap.validators.len() / 2 + 1) as u64 * WIGGLE_TIME_BEFORE_FORK_MILLIS; delay_ms += FIXED_BACKOFF_TIME_BEFORE_FORK_MILLIS + rand::rng().random_range(0..wiggle); } delay_ms } /// Verify block time for Ramanujan fork. - pub fn block_time_verify_for_ramanujan_fork(&self, snap: &Snapshot, header: &Header, parent: &Header) -> Result<(), BlockExecutionError> { + pub fn block_time_verify_for_ramanujan_fork( + &self, + snap: &Snapshot, + header: &Header, + parent: &Header, + ) -> Result<(), BlockExecutionError> { if self.spec.is_ramanujan_active_at_block(header.number) { let current_ts = calculate_millisecond_timestamp(header); let parent_ts = calculate_millisecond_timestamp(parent); let back_off_time = self.back_off_time(snap, parent, header); - + if current_ts < parent_ts + snap.block_interval + back_off_time { tracing::warn!( "Block time is too early, block_number: {}, ts: {:?}, parent_ts: {:?}, block_interval: {:?}, back_off_time: {:?}", @@ -73,8 +88,9 @@ where ChainSpec: EthChainSpec + BscHardforks + 'static, BscBlockValidationError::FutureBlock { block_number: header.number, hash: header.hash_slow(), - } - ).into()); + }, + ) + .into()); } } Ok(()) diff --git a/src/consensus/parlia/snapshot.rs b/src/consensus/parlia/snapshot.rs index acd18ed1..ccb872d8 100644 --- a/src/consensus/parlia/snapshot.rs +++ b/src/consensus/parlia/snapshot.rs @@ -27,10 +27,10 @@ pub const LORENTZ_TURN_LENGTH: u8 = 8; pub const MAXWELL_EPOCH_LENGTH: u64 = 1000; pub const MAXWELL_TURN_LENGTH: u8 = 16; -pub const DEFAULT_BLOCK_INTERVAL: u64 = 3000; // 3000 ms -pub const LORENTZ_BLOCK_INTERVAL: u64 = 1500; // 1500 ms -pub const MAXWELL_BLOCK_INTERVAL: u64 = 750; // 750 ms -pub const FERMI_BLOCK_INTERVAL: u64 = 450; // 450 ms +pub const DEFAULT_BLOCK_INTERVAL: u64 = 3000; // 3000 ms +pub const LORENTZ_BLOCK_INTERVAL: u64 = 1500; // 1500 ms +pub const MAXWELL_BLOCK_INTERVAL: u64 = 750; // 750 ms +pub const FERMI_BLOCK_INTERVAL: u64 = 450; // 450 ms /// Global metrics for vote attestation operations. static VOTE_METRICS: Lazy = Lazy::new(BscVoteMetrics::default); @@ -96,9 +96,9 @@ impl Snapshot { // Step 1: Build mapping with original order to maintain validator->vote_addr correspondence for (i, v) in validators.iter().enumerate() { - let info = ValidatorInfo { - index: 0, // Will be set after sorting - vote_addr: vote_addrs[i] + let info = ValidatorInfo { + index: 0, // Will be set after sorting + vote_addr: vote_addrs[i], }; validators_map.insert(*v, info); } @@ -117,10 +117,7 @@ impl Snapshot { // Sort first, then create map with indices validators.sort(); for (i, v) in validators.iter().enumerate() { - let info = ValidatorInfo { - index: i as u64 + 1, - vote_addr: VoteAddress::ZERO, - }; + let info = ValidatorInfo { index: i as u64 + 1, vote_addr: VoteAddress::ZERO }; validators_map.insert(*v, info); } } @@ -260,7 +257,9 @@ impl Snapshot { && (!is_bohr || !snap.recent_proposers.contains_key(&epoch_key)) { // Epoch change driven by new validator set / checkpoint header. - if let Some(tl) = turn_length { snap.turn_length = Some(tl) } + if let Some(tl) = turn_length { + snap.turn_length = Some(tl) + } if is_bohr { // BEP-404: Clear Miner History when Switching Validators Set @@ -287,10 +286,13 @@ impl Snapshot { // Step 1: Build mapping with original order to maintain validator->vote_addr correspondence for (i, v) in new_validators.iter().enumerate() { - validators_map.insert(*v, ValidatorInfo { - index: 0, // Will be set after sorting - vote_addr: vote_addrs[i] - }); + validators_map.insert( + *v, + ValidatorInfo { + index: 0, // Will be set after sorting + vote_addr: vote_addrs[i], + }, + ); } // Step 2: Sort validators @@ -306,10 +308,10 @@ impl Snapshot { // Pre-Luban: no vote addresses, just sort and create default entries new_validators.sort(); for (i, v) in new_validators.iter().enumerate() { - validators_map.insert(*v, ValidatorInfo { - index: i as u64 + 1, - vote_addr: VoteAddress::ZERO, - }); + validators_map.insert( + *v, + ValidatorInfo { index: i as u64 + 1, vote_addr: VoteAddress::ZERO }, + ); } } // Clean up fork hashes that exceed the new window after validator set change diff --git a/src/consensus/parlia/tests/snapshot_persistence.rs b/src/consensus/parlia/tests/snapshot_persistence.rs index c5bb8a8b..f6041e88 100644 --- a/src/consensus/parlia/tests/snapshot_persistence.rs +++ b/src/consensus/parlia/tests/snapshot_persistence.rs @@ -1,12 +1,8 @@ //! Unit tests for Parlia snapshot database persistence and retrieval. -use super::super::{ - provider::DbSnapshotProvider, - snapshot::Snapshot, - provider::SnapshotProvider, -}; -use alloy_primitives::{Address, B256, BlockHash}; -use reth_db::{init_db, mdbx::DatabaseArguments, Database, transaction::DbTx, cursor::DbCursorRO}; +use super::super::{provider::DbSnapshotProvider, provider::SnapshotProvider, snapshot::Snapshot}; +use alloy_primitives::{Address, BlockHash, B256}; +use reth_db::{cursor::DbCursorRO, init_db, mdbx::DatabaseArguments, transaction::DbTx, Database}; use std::sync::Arc; use uuid::Uuid; @@ -16,15 +12,15 @@ fn test_snapshot_database_persistence() -> eyre::Result<()> { // Initialize test database let db_path = std::env::temp_dir().join(format!("bsc_test_db_{}", Uuid::new_v4())); std::fs::create_dir_all(&db_path)?; - + let database = Arc::new(init_db(&db_path, DatabaseArguments::new(Default::default()))?); - + // Cleanup guard to ensure database is removed even if test fails let _cleanup_guard = TestCleanup { path: db_path.clone() }; - + // Create DbSnapshotProvider let provider = DbSnapshotProvider::new(database.clone(), 256); - + // Create test snapshots at checkpoint intervals let mut test_snapshots = Vec::new(); for i in 0..5 { @@ -32,36 +28,33 @@ fn test_snapshot_database_persistence() -> eyre::Result<()> { let snapshot = Snapshot { block_number, block_hash: B256::random(), - validators: vec![ - Address::random(), - Address::random(), - Address::random(), - ], + validators: vec![Address::random(), Address::random(), Address::random()], epoch_num: 200, turn_length: Some(1), ..Default::default() }; - + test_snapshots.push(snapshot); } - + // Insert snapshots for snapshot in &test_snapshots { provider.insert(snapshot.clone()); } - + // Verify snapshots can be retrieved for expected in &test_snapshots { - let retrieved = provider.snapshot_by_hash(&expected.block_hash) + let retrieved = provider + .snapshot_by_hash(&expected.block_hash) .unwrap_or_else(|| panic!("Snapshot at block {} should exist", expected.block_number)); - + assert_eq!(retrieved.block_number, expected.block_number); assert_eq!(retrieved.block_hash, expected.block_hash); assert_eq!(retrieved.validators.len(), expected.validators.len()); assert_eq!(retrieved.epoch_num, expected.epoch_num); assert_eq!(retrieved.turn_length, expected.turn_length); } - + Ok(()) } @@ -70,12 +63,12 @@ fn test_snapshot_database_persistence() -> eyre::Result<()> { fn test_snapshot_range_queries() -> eyre::Result<()> { let db_path = std::env::temp_dir().join(format!("bsc_test_db_{}", Uuid::new_v4())); std::fs::create_dir_all(&db_path)?; - + let database = Arc::new(init_db(&db_path, DatabaseArguments::new(Default::default()))?); let _cleanup_guard = TestCleanup { path: db_path.clone() }; - + let provider = DbSnapshotProvider::new(database.clone(), 256); - + // Insert snapshots at blocks 1024, 2048, 3072, 4096, 5120 let mut test_snapshots = Vec::new(); for i in 1..=6 { @@ -87,42 +80,45 @@ fn test_snapshot_range_queries() -> eyre::Result<()> { epoch_num: 200, ..Default::default() }; - + test_snapshots.push(snapshot.clone()); // only save 3 snapshots to DB if [1, 2, 5].contains(&i) { provider.insert(snapshot); } } - + // Test range queries - should find nearest predecessor let test_cases = vec![ - (BlockHash::random(), None), // Before first snapshot - (test_snapshots[0].block_hash, Some(1024)), // Exact match - (test_snapshots[1].block_hash, Some(2048)), // Exact match - (test_snapshots[2].block_hash, None), // not exist - (test_snapshots[3].block_hash, None), // not exist - (test_snapshots[4].block_hash, Some(5120)), // Last snapshot - (test_snapshots[5].block_hash, None), // After last snapshot - should find 5120 + (BlockHash::random(), None), // Before first snapshot + (test_snapshots[0].block_hash, Some(1024)), // Exact match + (test_snapshots[1].block_hash, Some(2048)), // Exact match + (test_snapshots[2].block_hash, None), // not exist + (test_snapshots[3].block_hash, None), // not exist + (test_snapshots[4].block_hash, Some(5120)), // Last snapshot + (test_snapshots[5].block_hash, None), // After last snapshot - should find 5120 ]; - + for (query_block, expected_block) in test_cases { let result = provider.snapshot_by_hash(&query_block); match expected_block { Some(expected) => { - let snapshot = result.unwrap_or_else(|| panic!("Should find snapshot for block {query_block}")); + let snapshot = result + .unwrap_or_else(|| panic!("Should find snapshot for block {query_block}")); assert_eq!(snapshot.block_number, expected, "Query for block {query_block} should return snapshot at block {expected}, got {}", snapshot.block_number); } None => { - assert!(result.is_none(), - "Query for block {query_block} should return None, got snapshot at block {}", - result.map(|s| s.block_number).unwrap_or(0)); + assert!( + result.is_none(), + "Query for block {query_block} should return None, got snapshot at block {}", + result.map(|s| s.block_number).unwrap_or(0) + ); } } } - + Ok(()) } @@ -131,12 +127,12 @@ fn test_snapshot_range_queries() -> eyre::Result<()> { fn test_direct_database_access() -> eyre::Result<()> { let db_path = std::env::temp_dir().join(format!("bsc_test_db_{}", Uuid::new_v4())); std::fs::create_dir_all(&db_path)?; - + let database = Arc::new(init_db(&db_path, DatabaseArguments::new(Default::default()))?); let _cleanup_guard = TestCleanup { path: db_path.clone() }; - + let provider = DbSnapshotProvider::new(database.clone(), 256); - + // Insert test snapshots let snapshot_count = 3; for i in 1..=snapshot_count { @@ -148,23 +144,25 @@ fn test_direct_database_access() -> eyre::Result<()> { epoch_num: 200, ..Default::default() }; - + provider.insert(snapshot); } - + // Check raw database table let tx = database.tx()?; let mut cursor = tx.cursor_read::()?; let mut count = 0; - + for item in cursor.walk(None)? { let (_key, _value) = item?; count += 1; } - - assert_eq!(count, snapshot_count, - "Database should contain {snapshot_count} snapshot entries, found {count}"); - + + assert_eq!( + count, snapshot_count, + "Database should contain {snapshot_count} snapshot entries, found {count}" + ); + Ok(()) } @@ -173,13 +171,13 @@ fn test_direct_database_access() -> eyre::Result<()> { fn test_snapshot_cache_behavior() -> eyre::Result<()> { let db_path = std::env::temp_dir().join(format!("bsc_test_db_{}", Uuid::new_v4())); std::fs::create_dir_all(&db_path)?; - + let database = Arc::new(init_db(&db_path, DatabaseArguments::new(Default::default()))?); let _cleanup_guard = TestCleanup { path: db_path.clone() }; - + // Small cache size to test eviction let provider = DbSnapshotProvider::new(database.clone(), 2); - + // Insert more snapshots than cache size let mut test_snapshots = Vec::new(); for i in 1..=5 { @@ -194,18 +192,19 @@ fn test_snapshot_cache_behavior() -> eyre::Result<()> { test_snapshots.push(snapshot.clone()); provider.insert(snapshot); } - + // All snapshots should still be retrievable (from DB if not in cache) for expected in &test_snapshots { - let snapshot = provider.snapshot_by_hash(&expected.block_hash) - .unwrap_or_else(|| panic!("Snapshot at block {} should be retrievable", expected.block_hash)); + let snapshot = provider.snapshot_by_hash(&expected.block_hash).unwrap_or_else(|| { + panic!("Snapshot at block {} should be retrievable", expected.block_hash) + }); assert_eq!(snapshot.block_number, expected.block_number); assert_eq!(snapshot.block_hash, expected.block_hash); assert_eq!(snapshot.validators.len(), expected.validators.len()); assert_eq!(snapshot.epoch_num, expected.epoch_num); assert_eq!(snapshot.turn_length, expected.turn_length); } - + Ok(()) } diff --git a/src/consensus/parlia/vote.rs b/src/consensus/parlia/vote.rs index 2959f49f..51d4e3b5 100644 --- a/src/consensus/parlia/vote.rs +++ b/src/consensus/parlia/vote.rs @@ -1,5 +1,5 @@ -use alloy_primitives::{keccak256, BlockNumber, B256, FixedBytes}; -use alloy_rlp::{RlpDecodable, RlpEncodable, Decodable}; +use alloy_primitives::{keccak256, BlockNumber, FixedBytes, B256}; +use alloy_rlp::{Decodable, RlpDecodable, RlpEncodable}; use bytes::Bytes; use serde::{Deserialize, Serialize}; @@ -19,7 +19,9 @@ pub type VoteAddress = FixedBytes<48>; pub type VoteSignature = FixedBytes<96>; /// `VoteData` represents one voting range that validators cast votes for fast-finality. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable, Serialize, Deserialize)] +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable, Serialize, Deserialize, +)] pub struct VoteData { /// The source block number (latest justified checkpoint). pub source_number: BlockNumber, @@ -33,7 +35,9 @@ pub struct VoteData { impl VoteData { /// Returns the Keccak-256 hash of the RLP-encoded `VoteData`. - pub fn hash(&self) -> B256 { keccak256(alloy_rlp::encode(self)) } + pub fn hash(&self) -> B256 { + keccak256(alloy_rlp::encode(self)) + } } /// `VoteEnvelope` represents a single signed vote from one validator. @@ -49,7 +53,9 @@ pub struct VoteEnvelope { impl VoteEnvelope { /// Returns the Keccak-256 hash of the RLP-encoded envelope. - pub fn hash(&self) -> B256 { keccak256(alloy_rlp::encode(self)) } + pub fn hash(&self) -> B256 { + keccak256(alloy_rlp::encode(self)) + } } /// `VoteAttestation` is the aggregated vote of a super-majority of validators. diff --git a/src/evm/precompiles/bls.rs b/src/evm/precompiles/bls.rs index 39904855..a0eb59b6 100644 --- a/src/evm/precompiles/bls.rs +++ b/src/evm/precompiles/bls.rs @@ -3,7 +3,7 @@ use alloy_primitives::Bytes; use bls_on_arkworks as bls; use revm::precompile::{ - u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, Precompile, PrecompileId, + u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use std::vec::Vec; @@ -32,10 +32,10 @@ fn bls_signature_validation_run(input: &[u8], gas_limit: u64) -> PrecompileResul let msg_and_sig_length = BLS_MSG_HASH_LENGTH + BLS_SIGNATURE_LENGTH; let input_length = input.len() as u64; - if (input_length <= msg_and_sig_length) || - !((input_length - msg_and_sig_length).is_multiple_of(BLS_SINGLE_PUBKEY_LENGTH)) + if (input_length <= msg_and_sig_length) + || !((input_length - msg_and_sig_length).is_multiple_of(BLS_SINGLE_PUBKEY_LENGTH)) { - return revert() + return revert(); } let msg_hash: &Vec = &input[..BLS_MSG_HASH_LENGTH as usize].to_vec(); @@ -44,7 +44,7 @@ fn bls_signature_validation_run(input: &[u8], gas_limit: u64) -> PrecompileResul // check signature format if bls::signature_to_point(&signature.to_vec()).is_err() { - return revert() + return revert(); } let pub_key_count = (input_length - msg_and_sig_length) / BLS_SINGLE_PUBKEY_LENGTH; @@ -53,22 +53,22 @@ fn bls_signature_validation_run(input: &[u8], gas_limit: u64) -> PrecompileResul // check pubkey format and push to pub_keys for i in 0..pub_key_count { - let pub_key = &pub_keys_data[i as usize * BLS_SINGLE_PUBKEY_LENGTH as usize.. - (i + 1) as usize * BLS_SINGLE_PUBKEY_LENGTH as usize]; + let pub_key = &pub_keys_data[i as usize * BLS_SINGLE_PUBKEY_LENGTH as usize + ..(i + 1) as usize * BLS_SINGLE_PUBKEY_LENGTH as usize]; if !bls::key_validate(&pub_key.to_vec()) { - return revert() + return revert(); } pub_keys.push(pub_key.to_vec()); msg_hashes.push(msg_hash.clone().to_vec()); } if pub_keys.is_empty() { - return revert() + return revert(); } // verify signature let mut output = Bytes::from(vec![1]); - if (pub_keys.len() == 1 && !bls::verify(&pub_keys[0], msg_hash, signature, &BLS_DST.to_vec())) || - !bls::aggregate_verify(pub_keys, msg_hashes, signature, &BLS_DST.to_vec()) + if (pub_keys.len() == 1 && !bls::verify(&pub_keys[0], msg_hash, signature, &BLS_DST.to_vec())) + || !bls::aggregate_verify(pub_keys, msg_hashes, signature, &BLS_DST.to_vec()) { output = Bytes::from(vec![]); } @@ -84,8 +84,8 @@ fn calc_gas_cost(input: &[u8]) -> u64 { let single_pubkey_length = BLS_SINGLE_PUBKEY_LENGTH; let input_length = input.len() as u64; - if (input_length <= msg_length) || - !((input_length - msg_length).is_multiple_of(single_pubkey_length)) + if (input_length <= msg_length) + || !((input_length - msg_length).is_multiple_of(single_pubkey_length)) { return BLS_SIGNATURE_VALIDATION_BASE; } diff --git a/src/evm/precompiles/cometbft.rs b/src/evm/precompiles/cometbft.rs index c0572a67..097f7c3e 100644 --- a/src/evm/precompiles/cometbft.rs +++ b/src/evm/precompiles/cometbft.rs @@ -14,15 +14,21 @@ use cometbft_light_client_verifier::{ use cometbft_proto::types::v1::LightBlock as TmLightBlock; use prost::Message; use revm::precompile::{ - u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, Precompile, PrecompileId, + u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use std::{borrow::ToOwned, string::String, vec::Vec}; -pub(crate) const COMETBFT_LIGHT_BLOCK_VALIDATION: Precompile = - Precompile::new(PrecompileId::Identity, u64_to_address(103), cometbft_light_block_validation_run); +pub(crate) const COMETBFT_LIGHT_BLOCK_VALIDATION: Precompile = Precompile::new( + PrecompileId::Identity, + u64_to_address(103), + cometbft_light_block_validation_run, +); -pub(crate) const COMETBFT_LIGHT_BLOCK_VALIDATION_BEFORE_HERTZ: Precompile = - Precompile::new(PrecompileId::Identity, u64_to_address(103), cometbft_light_block_validation_run_before_hertz); +pub(crate) const COMETBFT_LIGHT_BLOCK_VALIDATION_BEFORE_HERTZ: Precompile = Precompile::new( + PrecompileId::Identity, + u64_to_address(103), + cometbft_light_block_validation_run_before_hertz, +); const UINT64_TYPE_LENGTH: u64 = 8; const CONSENSUS_STATE_LENGTH_BYTES_LENGTH: u64 = 32; @@ -36,15 +42,15 @@ const VALIDATOR_VOTING_POWER_LENGTH: u64 = 8; const RELAYER_ADDRESS_LENGTH: u64 = 20; const RELAYER_BLS_KEY_LENGTH: u64 = 48; -const SINGLE_VALIDATOR_BYTES_LENGTH: u64 = VALIDATOR_PUBKEY_LENGTH + - VALIDATOR_VOTING_POWER_LENGTH + - RELAYER_ADDRESS_LENGTH + - RELAYER_BLS_KEY_LENGTH; +const SINGLE_VALIDATOR_BYTES_LENGTH: u64 = VALIDATOR_PUBKEY_LENGTH + + VALIDATOR_VOTING_POWER_LENGTH + + RELAYER_ADDRESS_LENGTH + + RELAYER_BLS_KEY_LENGTH; -const MAX_CONSENSUS_STATE_LENGTH: u64 = CHAIN_ID_LENGTH + - HEIGHT_LENGTH + - VALIDATOR_SET_HASH_LENGTH + - 99 * SINGLE_VALIDATOR_BYTES_LENGTH; +const MAX_CONSENSUS_STATE_LENGTH: u64 = CHAIN_ID_LENGTH + + HEIGHT_LENGTH + + VALIDATOR_SET_HASH_LENGTH + + 99 * SINGLE_VALIDATOR_BYTES_LENGTH; fn cometbft_light_block_validation_run(input: &[u8], gas_limit: u64) -> PrecompileResult { cometbft_light_block_validation_run_inner(input, gas_limit, true) @@ -112,8 +118,8 @@ fn decode_light_block_validation_input(input: &[u8]) -> DecodeLightBlockResult { } let cs_length = u64::from_be_bytes( - input[CONSENSUS_STATE_LENGTH_BYTES_LENGTH as usize - UINT64_TYPE_LENGTH as usize.. - CONSENSUS_STATE_LENGTH_BYTES_LENGTH as usize] + input[CONSENSUS_STATE_LENGTH_BYTES_LENGTH as usize - UINT64_TYPE_LENGTH as usize + ..CONSENSUS_STATE_LENGTH_BYTES_LENGTH as usize] .try_into() .unwrap(), ); @@ -128,8 +134,8 @@ fn decode_light_block_validation_input(input: &[u8]) -> DecodeLightBlockResult { } let decode_input = Bytes::from( - input[CONSENSUS_STATE_LENGTH_BYTES_LENGTH as usize.. - (CONSENSUS_STATE_LENGTH_BYTES_LENGTH + cs_length) as usize] + input[CONSENSUS_STATE_LENGTH_BYTES_LENGTH as usize + ..(CONSENSUS_STATE_LENGTH_BYTES_LENGTH + cs_length) as usize] .to_vec(), ); let consensus_state = decode_consensus_state(&decode_input)?; @@ -234,10 +240,10 @@ impl ConsensusState { fn encode(&self) -> Result { let validator_set_length = self.validators.validators().len(); - let serialize_length = (CHAIN_ID_LENGTH + - HEIGHT_LENGTH + - VALIDATOR_SET_HASH_LENGTH + - validator_set_length as u64 * SINGLE_VALIDATOR_BYTES_LENGTH) + let serialize_length = (CHAIN_ID_LENGTH + + HEIGHT_LENGTH + + VALIDATOR_SET_HASH_LENGTH + + validator_set_length as u64 * SINGLE_VALIDATOR_BYTES_LENGTH) as usize; if serialize_length > MAX_CONSENSUS_STATE_LENGTH as usize { return Err(BscPrecompileError::CometBftEncodeConsensusStateFailed.into()); @@ -297,8 +303,8 @@ type DecodeConsensusStateResult = Result; fn decode_consensus_state(input: &Bytes) -> DecodeConsensusStateResult { let minimum_length = CHAIN_ID_LENGTH + HEIGHT_LENGTH + VALIDATOR_SET_HASH_LENGTH; let input_length = input.len() as u64; - if input_length <= minimum_length || - !(input_length - minimum_length).is_multiple_of(SINGLE_VALIDATOR_BYTES_LENGTH) + if input_length <= minimum_length + || !(input_length - minimum_length).is_multiple_of(SINGLE_VALIDATOR_BYTES_LENGTH) { return Err(BscPrecompileError::InvalidInput.into()); } @@ -324,25 +330,25 @@ fn decode_consensus_state(input: &Bytes) -> DecodeConsensusStateResult { let validator_set_bytes = input[pos as usize..].to_vec(); let mut validator_set = Vec::with_capacity(validator_set_length as usize); for i in 0..validator_set_length { - let validator = &validator_set_bytes[i as usize * SINGLE_VALIDATOR_BYTES_LENGTH as usize.. - (i + 1) as usize * SINGLE_VALIDATOR_BYTES_LENGTH as usize]; + let validator = &validator_set_bytes[i as usize * SINGLE_VALIDATOR_BYTES_LENGTH as usize + ..(i + 1) as usize * SINGLE_VALIDATOR_BYTES_LENGTH as usize]; let voting_power = u64::from_be_bytes( - validator[VALIDATOR_PUBKEY_LENGTH as usize.. - (VALIDATOR_PUBKEY_LENGTH + VALIDATOR_VOTING_POWER_LENGTH) as usize] + validator[VALIDATOR_PUBKEY_LENGTH as usize + ..(VALIDATOR_PUBKEY_LENGTH + VALIDATOR_VOTING_POWER_LENGTH) as usize] .try_into() .unwrap(), ); let relayer_address = Bytes::from( - validator[(VALIDATOR_PUBKEY_LENGTH + VALIDATOR_VOTING_POWER_LENGTH) as usize.. - (VALIDATOR_PUBKEY_LENGTH + VALIDATOR_VOTING_POWER_LENGTH + RELAYER_ADDRESS_LENGTH) + validator[(VALIDATOR_PUBKEY_LENGTH + VALIDATOR_VOTING_POWER_LENGTH) as usize + ..(VALIDATOR_PUBKEY_LENGTH + VALIDATOR_VOTING_POWER_LENGTH + RELAYER_ADDRESS_LENGTH) as usize] .to_vec(), ); let relayer_bls_key = Bytes::from( - validator[(VALIDATOR_PUBKEY_LENGTH + - VALIDATOR_VOTING_POWER_LENGTH + - RELAYER_ADDRESS_LENGTH) as usize..] + validator[(VALIDATOR_PUBKEY_LENGTH + + VALIDATOR_VOTING_POWER_LENGTH + + RELAYER_ADDRESS_LENGTH) as usize..] .to_vec(), ); let pk = match PublicKey::from_raw_ed25519(&validator[..VALIDATOR_PUBKEY_LENGTH as usize]) { diff --git a/src/evm/precompiles/double_sign.rs b/src/evm/precompiles/double_sign.rs index f591de43..a70fa431 100644 --- a/src/evm/precompiles/double_sign.rs +++ b/src/evm/precompiles/double_sign.rs @@ -5,13 +5,16 @@ use alloy_primitives::{keccak256, BlockNumber, Bytes, ChainId, B256, B512, U256} use alloy_rlp::{Decodable, RlpDecodable, RlpEncodable}; use core::cmp::Ordering; use revm::precompile::{ - secp256k1, u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, - Precompile, PrecompileId, + secp256k1, u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, + PrecompileResult, }; /// Double sign evidence validation precompile for BSC. -pub(crate) const DOUBLE_SIGN_EVIDENCE_VALIDATION: Precompile = - Precompile::new(PrecompileId::Identity, u64_to_address(104), double_sign_evidence_validation_run); +pub(crate) const DOUBLE_SIGN_EVIDENCE_VALIDATION: Precompile = Precompile::new( + PrecompileId::Identity, + u64_to_address(104), + double_sign_evidence_validation_run, +); const EXTRA_SEAL_LENGTH: usize = 65; @@ -85,7 +88,7 @@ fn double_sign_evidence_validation_run(input: &[u8], gas_limit: u64) -> Precompi }; let Ok(evidence) = DoubleSignEvidence::decode(&mut input.iter().as_ref()) else { - return revert() + return revert(); }; let Ok(header1) = Header::decode(&mut evidence.header_bytes1.as_ref()) else { return revert() }; diff --git a/src/evm/precompiles/iavl.rs b/src/evm/precompiles/iavl.rs index 156b142c..d032a3ce 100644 --- a/src/evm/precompiles/iavl.rs +++ b/src/evm/precompiles/iavl.rs @@ -1,7 +1,7 @@ use alloy_primitives::Bytes; use parity_bytes::BytesRef; use revm::precompile::{ - u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, Precompile, PrecompileId, + u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use tendermint::lite::iavl_proof; diff --git a/src/evm/precompiles/tendermint.rs b/src/evm/precompiles/tendermint.rs index 574ea573..5103984c 100644 --- a/src/evm/precompiles/tendermint.rs +++ b/src/evm/precompiles/tendermint.rs @@ -3,7 +3,7 @@ use alloy_primitives::Bytes; use parity_bytes::BytesRef; use revm::precompile::{ - u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, Precompile, PrecompileId, + u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use tendermint::lite::light_client; @@ -12,8 +12,11 @@ pub(crate) const TENDERMINT_HEADER_VALIDATION: Precompile = Precompile::new(PrecompileId::Identity, u64_to_address(100), tendermint_header_validation_run); /// Tendermint precompile for BSC after Nano hardfork. -pub(crate) const TENDERMINT_HEADER_VALIDATION_NANO: Precompile = - Precompile::new(PrecompileId::Identity, u64_to_address(100), tendermint_header_validation_run_nano); +pub(crate) const TENDERMINT_HEADER_VALIDATION_NANO: Precompile = Precompile::new( + PrecompileId::Identity, + u64_to_address(100), + tendermint_header_validation_run_nano, +); /// Run the Tendermint header validation precompile after Nano hardfork. fn tendermint_header_validation_run_nano(input: &[u8], _gas_limit: u64) -> PrecompileResult { diff --git a/src/evm/precompiles/tm_secp256k1.rs b/src/evm/precompiles/tm_secp256k1.rs index 46560bf1..7c62330d 100644 --- a/src/evm/precompiles/tm_secp256k1.rs +++ b/src/evm/precompiles/tm_secp256k1.rs @@ -2,14 +2,17 @@ use alloy_primitives::Bytes; use revm::precompile::{ - u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, Precompile, PrecompileId, + u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use secp256k1::{ecdsa, Message, PublicKey}; use tendermint::{account, public_key}; /// Tendermint SECP256K1 signature recover precompile for BSC. -pub(crate) const TM_SECP256K1_SIGNATURE_RECOVER: Precompile = - Precompile::new(PrecompileId::Identity, u64_to_address(105), tm_secp256k1_signature_recover_run); +pub(crate) const TM_SECP256K1_SIGNATURE_RECOVER: Precompile = Precompile::new( + PrecompileId::Identity, + u64_to_address(105), + tm_secp256k1_signature_recover_run, +); const SECP256K1_PUBKEY_LENGTH: usize = 33; const SECP256K1_SIGNATURE_LENGTH: usize = 64; @@ -30,8 +33,8 @@ fn tm_secp256k1_signature_recover_run(input: &[u8], gas_limit: u64) -> Precompil } let input_length = input.len(); - if input_length != - SECP256K1_PUBKEY_LENGTH + SECP256K1_SIGNATURE_LENGTH + SECP256K1_SIGNATURE_MSGHASH_LENGTH + if input_length + != SECP256K1_PUBKEY_LENGTH + SECP256K1_SIGNATURE_LENGTH + SECP256K1_SIGNATURE_MSGHASH_LENGTH { return Err(PrecompileError::other("invalid input")); } diff --git a/src/hardforks/mod.rs b/src/hardforks/mod.rs index 7780d528..79a5450d 100644 --- a/src/hardforks/mod.rs +++ b/src/hardforks/mod.rs @@ -134,7 +134,12 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Kepler`] is firstly active at a given /// timestamp and parent timestamp. - fn is_kepler_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_kepler_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_kepler_active_at_timestamp(parent_number, parent_timestamp) && self.is_kepler_active_at_timestamp(block_number, timestamp) @@ -142,13 +147,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Kepler`] is active at a given timestamp. fn is_kepler_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Kepler).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Kepler).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Feynman`] is firstly active at a given /// timestamp and parent timestamp. - fn is_feynman_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_feynman_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_feynman_active_at_timestamp(parent_number, parent_timestamp) && self.is_feynman_active_at_timestamp(block_number, timestamp) @@ -156,8 +166,8 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Feynman`] is active at a given timestamp. fn is_feynman_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Feynman).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Feynman).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::FeynmanFix`] is firstly active at a given @@ -175,13 +185,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::FeynmanFix`] is active at a given timestamp. fn is_feynman_fix_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::FeynmanFix).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::FeynmanFix).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Haber`] is firstly active at a given timestamp /// and parent timestamp. - fn is_haber_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_haber_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_haber_active_at_timestamp(parent_number, parent_timestamp) && self.is_haber_active_at_timestamp(block_number, timestamp) @@ -189,13 +204,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Haber`] is active at a given timestamp. fn is_haber_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Haber).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Haber).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Tycho`] is firstly active at a given /// timestamp and parent timestamp. - fn is_tycho_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_tycho_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_tycho_active_at_timestamp(parent_number, parent_timestamp) && self.is_tycho_active_at_timestamp(block_number, timestamp) @@ -203,13 +223,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Tycho`] is active at a given timestamp. fn is_tycho_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Tycho).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Tycho).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::HaberFix`] is firstly active at a given /// timestamp and parent timestamp. - fn is_haber_fix_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_haber_fix_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_haber_fix_active_at_timestamp(parent_number, parent_timestamp) && self.is_haber_fix_active_at_timestamp(block_number, timestamp) @@ -217,13 +242,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::HaberFix`] is active at a given timestamp. fn is_haber_fix_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::HaberFix).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::HaberFix).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Cancun`] is firstly active at a given /// timestamp and parent timestamp. - fn is_cancun_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_cancun_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !BscHardforks::is_cancun_active_at_timestamp(self, parent_number, parent_timestamp) && BscHardforks::is_cancun_active_at_timestamp(self, block_number, timestamp) @@ -231,13 +261,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Cancun`] is active at a given timestamp. fn is_cancun_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Cancun).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Cancun).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Bohr`] is firstly active at a given /// timestamp and parent timestamp. - fn is_bohr_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_bohr_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !BscHardforks::is_bohr_active_at_timestamp(self, parent_number, parent_timestamp) && BscHardforks::is_bohr_active_at_timestamp(self, block_number, timestamp) @@ -245,8 +280,8 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Bohr`] is active at a given timestamp. fn is_bohr_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Bohr).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Bohr).active_at_timestamp(timestamp) } /// Convenience method to check if [`EthereumHardfork::Prague`] is active at a given block /// and timestamp. @@ -270,7 +305,12 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Pascal`] is firstly active at a given /// timestamp and parent timestamp. - fn is_pascal_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_pascal_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_pascal_active_at_timestamp(parent_number, parent_timestamp) && self.is_pascal_active_at_timestamp(block_number, timestamp) @@ -278,13 +318,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Pascal`] is active at a given timestamp. fn is_pascal_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Pascal).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Pascal).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Lorentz`] is firstly active at a given /// timestamp and parent timestamp. - fn is_lorentz_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_lorentz_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_lorentz_active_at_timestamp(parent_number, parent_timestamp) && self.is_lorentz_active_at_timestamp(block_number, timestamp) @@ -292,13 +337,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Lorentz`] is active at a given timestamp. fn is_lorentz_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Lorentz).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Lorentz).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Maxwell`] is firstly active at a given /// timestamp and parent timestamp. - fn is_maxwell_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_maxwell_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_maxwell_active_at_timestamp(parent_number, parent_timestamp) && self.is_maxwell_active_at_timestamp(block_number, timestamp) @@ -306,13 +356,18 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Maxwell`] is active at a given timestamp. fn is_maxwell_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Maxwell).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Maxwell).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Fermi`] is firstly active at a given /// timestamp and parent timestamp. - fn is_fermi_transition_at_timestamp(&self, block_number: u64, timestamp: u64, parent_timestamp: u64) -> bool { + fn is_fermi_transition_at_timestamp( + &self, + block_number: u64, + timestamp: u64, + parent_timestamp: u64, + ) -> bool { let parent_number = block_number.saturating_sub(1); !self.is_fermi_active_at_timestamp(parent_number, parent_timestamp) && self.is_fermi_active_at_timestamp(block_number, timestamp) @@ -320,8 +375,8 @@ pub trait BscHardforks: EthereumHardforks { /// Convenience method to check if [`BscHardfork::Fermi`] is active at a given timestamp. fn is_fermi_active_at_timestamp(&self, block_number: u64, timestamp: u64) -> bool { - self.is_london_active_at_block(block_number) && - self.bsc_fork_activation(BscHardfork::Fermi).active_at_timestamp(timestamp) + self.is_london_active_at_block(block_number) + && self.bsc_fork_activation(BscHardfork::Fermi).active_at_timestamp(timestamp) } /// Convenience method to check if [`BscHardfork::Osaka`] is firstly active at a given diff --git a/src/lib.rs b/src/lib.rs index a5f11187..38651ba2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "bench-test")] +pub mod bench; pub mod chainspec; pub mod consensus; pub mod evm; @@ -7,7 +9,7 @@ pub mod node; pub mod rpc; pub mod shared; pub use node::primitives::BscPrimitives; -pub use node::primitives::{BscBlock, BscBlockBody, BscBlobTransactionSidecar}; +pub use node::primitives::{BscBlobTransactionSidecar, BscBlock, BscBlockBody}; mod system_contracts; pub use system_contracts::SLASH_CONTRACT; pub use system_contracts::{encode_add_node_ids_call, encode_remove_node_ids_call}; diff --git a/src/metrics.rs b/src/metrics.rs index b660619c..6d859144 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -184,6 +184,21 @@ pub struct BscMinerMetrics { /// Total number of blocks produced pub blocks_produced_total: Counter, + /// Total number of rebuild attempts after the initial payload build. + pub payload_retries_total: Counter, + + /// Time spent waiting between a completed candidate and the next rebuild/seal decision. + pub payload_retry_wait_seconds: Histogram, + + /// Time spent waiting for the first viable candidate during best-payload return. + pub payload_first_candidate_wait_seconds: Histogram, + + /// Time from a candidate becoming ready until it is submitted to the result worker. + pub payload_ready_to_submit_seconds: Histogram, + + /// Total number of times a rebuild was skipped because the remaining budget was too small. + pub payload_rebuild_skipped_total: Counter, + /// Block broadcast delay in nanoseconds (time from block timestamp to broadcast time) /// This measures how long it takes from block creation to network broadcast /// Note: Value is stored in nanoseconds to match Golang implementation diff --git a/src/node/engine.rs b/src/node/engine.rs index 64f5a4c8..37b77834 100644 --- a/src/node/engine.rs +++ b/src/node/engine.rs @@ -1,12 +1,12 @@ +use crate::BscBlock; use crate::{ + BscPrimitives, node::{ + BscNode, engine_api::payload::BscPayloadTypes, miner::{BscMiner, MiningConfig}, - BscNode, }, - BscPrimitives, }; -use crate::BscBlock; use crate::consensus::parlia::VoteAddress; use alloy_primitives::Address; use alloy_eips::eip7685::Requests; @@ -14,7 +14,7 @@ use alloy_primitives::U256; use reth::transaction_pool::PoolTransaction; use reth::{ api::FullNodeTypes, - builder::{components::PayloadServiceBuilder, BuilderContext}, + builder::{BuilderContext, components::PayloadServiceBuilder}, payload::{PayloadBuilderHandle, PayloadServiceCommand}, transaction_pool::TransactionPool, }; diff --git a/src/node/engine_api/validator_tests.rs b/src/node/engine_api/validator_tests.rs index 8c62af1c..fe5eb816 100644 --- a/src/node/engine_api/validator_tests.rs +++ b/src/node/engine_api/validator_tests.rs @@ -27,7 +27,7 @@ mod tests { difficulty: U256::from(2), ..Default::default() }; - + BscBlock { header, body: BscBlockBody { @@ -41,7 +41,7 @@ mod tests { fn test_bsc_engine_validator_creation() { let chain_spec = Arc::new(BscChainSpec::from(bsc_mainnet())); let validator = BscEngineValidator::new(chain_spec); - + // Validator should be created successfully assert!(std::mem::size_of_val(&validator) > 0); } @@ -51,7 +51,7 @@ mod tests { let parent_hash = B256::random(); let block = create_test_block(1, parent_hash); let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.parent_hash(), parent_hash); } @@ -61,7 +61,7 @@ mod tests { let block = create_test_block(1, parent_hash); let expected_hash = block.header.hash_slow(); let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.block_hash(), expected_hash); } @@ -99,7 +99,7 @@ mod tests { let block_number = 12345; let block = create_test_block(block_number, B256::random()); let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.block_number(), block_number); } @@ -108,7 +108,7 @@ mod tests { let block = create_test_block(1, B256::random()); let expected_timestamp = block.header.timestamp; let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.timestamp(), expected_timestamp); } @@ -117,7 +117,7 @@ mod tests { let mut block = create_test_block(1, B256::random()); block.header.gas_used = 1_000_000; let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.gas_used(), 1_000_000); } @@ -125,7 +125,7 @@ mod tests { fn test_execution_data_withdrawals_none() { let block = create_test_block(1, B256::random()); let execution_data = BscExecutionData::new(block); - + // BSC doesn't support withdrawals assert!(execution_data.withdrawals().is_none()); } @@ -134,7 +134,7 @@ mod tests { fn test_execution_data_parent_beacon_block_root_none() { let block = create_test_block(1, B256::random()); let execution_data = BscExecutionData::new(block); - + // BSC doesn't use parent beacon block root assert!(execution_data.parent_beacon_block_root().is_none()); } @@ -143,7 +143,7 @@ mod tests { fn test_engine_validator_debug_format() { let chain_spec = Arc::new(BscChainSpec::from(bsc_mainnet())); let validator = BscEngineValidator::new(chain_spec); - + let debug_str = format!("{:?}", validator); assert!(!debug_str.is_empty()); } @@ -152,9 +152,9 @@ mod tests { fn test_engine_validator_clone() { let chain_spec = Arc::new(BscChainSpec::from(bsc_mainnet())); let validator = BscEngineValidator::new(chain_spec); - + let cloned_validator = validator.clone(); - + // Both validators should be usable assert!(std::mem::size_of_val(&validator) > 0); assert!(std::mem::size_of_val(&cloned_validator) > 0); @@ -164,7 +164,7 @@ mod tests { fn test_execution_data_serialization() { let block = create_test_block(1, B256::random()); let execution_data = BscExecutionData::new(block); - + // Test that BscExecutionData can be serialized let serialized = serde_json::to_string(&execution_data); assert!(serialized.is_ok(), "ExecutionData should be serializable"); @@ -174,11 +174,11 @@ mod tests { fn test_execution_data_deserialization() { let block = create_test_block(1, B256::random()); let execution_data = BscExecutionData::new(block); - + // Serialize and then deserialize let serialized = serde_json::to_string(&execution_data).unwrap(); let deserialized: Result = serde_json::from_str(&serialized); - + assert!(deserialized.is_ok(), "ExecutionData should be deserializable"); } @@ -187,7 +187,7 @@ mod tests { let mut block = create_test_block(1, B256::random()); block.header.gas_used = 0; let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.gas_used(), 0); } @@ -197,22 +197,22 @@ mod tests { let gas_limit = block.header.gas_limit; block.header.gas_used = gas_limit; let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.gas_used(), gas_limit); } #[test] fn test_execution_data_with_different_difficulties() { let difficulties = vec![ - U256::from(1), // DIFF_NOTURN - U256::from(2), // DIFF_INTURN + U256::from(1), + U256::from(2), ]; - + for difficulty in difficulties { let mut block = create_test_block(1, B256::random()); block.header.difficulty = difficulty; let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.block_number(), 1); } } @@ -221,16 +221,16 @@ mod tests { fn test_execution_data_with_different_timestamps() { let timestamps = vec![ 1234567890u64, - 1640000000u64, // ~2022 - 1700000000u64, // ~2023 - 1740000000u64, // ~2025 + 1640000000u64, + 1700000000u64, + 1740000000u64, ]; - + for timestamp in timestamps { let mut block = create_test_block(1, B256::random()); block.header.timestamp = timestamp; let execution_data = BscExecutionData::new(block); - + assert_eq!(execution_data.timestamp(), timestamp); } } diff --git a/src/node/evm/assembler.rs b/src/node/evm/assembler.rs index 0ca23e72..adb5bb38 100644 --- a/src/node/evm/assembler.rs +++ b/src/node/evm/assembler.rs @@ -9,7 +9,7 @@ use crate::{ evm::config::{BscBlockExecutionCtx, BscBlockExecutorFactory}, miner::util::finalize_new_header, primitives::{BscBlock, BscBlockBody}, - } + }, }; use alloy_consensus::{proofs, BlockBody, Header, Transaction, TxReceipt, EMPTY_OMMER_ROOT_HASH}; use alloy_primitives::{keccak256, B256}; @@ -29,9 +29,8 @@ use revm::context_interface::block::Block; use revm::database::BundleState; use std::sync::Arc; - /// BSC block assembler input that mirrors BlockAssemblerInput but is not #[non_exhaustive] -/// +/// /// This allows us to construct the input in external crates without being limited by /// the #[non_exhaustive] attribute on the original BlockAssemblerInput. pub struct BscBlockAssemblerInput<'a, 'b, F: BlockExecutorFactory, H = Header> { @@ -67,14 +66,14 @@ pub struct BscBlockAssembler { pub(crate) parlia: Arc>, } -impl BscBlockAssembler +impl BscBlockAssembler where ChainSpec: EthChainSpec + BscHardforks + 'static, { pub fn new(chain_spec: Arc) -> Self { - Self { - chain_spec: chain_spec.clone(), - extra_data: Default::default(), + Self { + chain_spec: chain_spec.clone(), + extra_data: Default::default(), parlia: Arc::new(Parlia::new(chain_spec, 200)), } } @@ -117,7 +116,11 @@ where let mut withdrawals = None; let mut parent_beacon_block_root = None; let mut requests_hash = None; - if BscHardforks::is_cancun_active_at_timestamp(self.chain_spec.as_ref(), block_number, timestamp) { + if BscHardforks::is_cancun_active_at_timestamp( + self.chain_spec.as_ref(), + block_number, + timestamp, + ) { withdrawals_root = Some(EMPTY_WITHDRAWALS_HASH); withdrawals = Some(Withdrawals::new(vec![])); if self.chain_spec.is_bohr_active_at_timestamp(block_number, timestamp) { @@ -131,7 +134,11 @@ where let mut excess_blob_gas = None; let mut blob_gas_used = None; - if BscHardforks::is_cancun_active_at_timestamp(self.chain_spec.as_ref(), block_number, timestamp) { + if BscHardforks::is_cancun_active_at_timestamp( + self.chain_spec.as_ref(), + block_number, + timestamp, + ) { blob_gas_used = Some(transactions.iter().map(|tx| tx.blob_gas_used().unwrap_or_default()).sum()); excess_blob_gas = next_block_excess_blob_gas_with_mendel( @@ -186,7 +193,6 @@ where }, }) } - } impl BlockAssembler for BscBlockAssembler @@ -235,13 +241,14 @@ where let withdrawals_root = withdrawals.as_deref().map(|w| proofs::calculate_withdrawals_root(w)); - let requests_hash = self.chain_spec.is_prague_active_at_block_and_timestamp(block_number, timestamp) + let requests_hash = self + .chain_spec + .is_prague_active_at_block_and_timestamp(block_number, timestamp) .then(|| requests.requests_hash()); let mut excess_blob_gas = None; let mut blob_gas_used = None; - if BscHardforks::is_cancun_active_at_timestamp(&*self.chain_spec, block_number, timestamp) { blob_gas_used = Some(transactions.iter().map(|tx| tx.blob_gas_used().unwrap_or_default()).sum()); @@ -284,8 +291,9 @@ where excess_blob_gas, requests_hash, }; - - { // finalize_new_header + + { + // finalize_new_header let parent_header = crate::node::evm::util::HEADER_CACHE_READER .lock() .unwrap() @@ -296,12 +304,13 @@ where .snapshot_by_hash(&header.parent_hash) .ok_or(BlockExecutionError::msg("Failed to get snapshot from snapshot provider"))?; finalize_new_header( - self.parlia.clone(), - &parent_snap, - &parent_header, + self.parlia.clone(), + &parent_snap, + &parent_header, &mut header, &snapshot_provider, - ).map_err(|e| BlockExecutionError::msg(format!("Failed to finalize header: {}", e)))?; + ) + .map_err(|e| BlockExecutionError::msg(format!("Failed to finalize header: {}", e)))?; let header_hash = keccak256(alloy_rlp::encode(&header)); tracing::debug!("Succeed to finalize header, block_number={}, hash=0x{:x}, parent_hash=0x{:x}, txs={}", diff --git a/src/node/evm/error.rs b/src/node/evm/error.rs index d616eff4..2e01cd59 100644 --- a/src/node/evm/error.rs +++ b/src/node/evm/error.rs @@ -1,10 +1,10 @@ //! Error types for the Bsc EVM module. -use alloy_primitives::{Address, BlockHash, BlockNumber, B256, U256}; use crate::consensus::parlia::error::ParliaConsensusError; +use alloy_primitives::{Address, BlockHash, BlockNumber, B256, U256}; use reth_evm::execute::{BlockExecutionError, BlockValidationError}; -use reth_provider::ProviderError; use reth_primitives::{GotExpected, GotExpectedBoxed}; +use reth_provider::ProviderError; /// BSC specific block validation error #[derive(thiserror::Error, Debug, Clone)] @@ -17,7 +17,7 @@ pub enum BscBlockValidationError { /// The block hash hash: B256, }, - + /// Error when the system txs are more than expected #[error("unexpected system tx")] UnexpectedSystemTx, @@ -191,41 +191,43 @@ pub enum BscBlockExecutionError { impl From for BlockExecutionError { fn from(err: BscBlockExecutionError) -> Self { // Update execution errors metric for all types of errors - use once_cell::sync::Lazy; use crate::metrics::{BscConsensusMetrics, BscExecutorMetrics}; - static CONSENSUS_METRICS: Lazy = Lazy::new(BscConsensusMetrics::default); + use once_cell::sync::Lazy; + static CONSENSUS_METRICS: Lazy = + Lazy::new(BscConsensusMetrics::default); static EXECUTOR_METRICS: Lazy = Lazy::new(BscExecutorMetrics::default); EXECUTOR_METRICS.execution_errors_total.increment(1); - + match err { BscBlockExecutionError::Validation(validation_err) => { // Update bad blocks metric CONSENSUS_METRICS.bad_blocks_total.increment(1); - + // TODO: now use DepositRequestDecode as the validation error carrier, // but we should refine it by rewrite some validation error types in reth engine-tree. - // Note: Validation errors will be identified in the engine-tree and treated as invalid blocks. - Self::Validation(BlockValidationError::DepositRequestDecode( - format!("BSC validation error: {}", validation_err) - )) + // Note: Validation errors will be identified in the engine-tree and treated as invalid blocks. + Self::Validation(BlockValidationError::DepositRequestDecode(format!( + "BSC validation error: {}", + validation_err + ))) } - - BscBlockExecutionError::SnapshotNotFound | - BscBlockExecutionError::EthCallFailed | - BscBlockExecutionError::GetTopValidatorsFailed | - BscBlockExecutionError::ParentUnknown { .. } | - BscBlockExecutionError::ApplySnapshotFailed | - BscBlockExecutionError::UnknownHeader { .. } | - BscBlockExecutionError::VoteAddrNotFoundInSnap { .. } | - BscBlockExecutionError::BLSTInnerError | - BscBlockExecutionError::ProviderInnerError { .. } | - BscBlockExecutionError::SystemContractUpgradeError | - BscBlockExecutionError::FailedToSignSystemTransaction { .. } | - BscBlockExecutionError::GlobalSignerNotInitializedForMiningMode => { - // Note: Internal errors will be identified in the engine-tree, + + BscBlockExecutionError::SnapshotNotFound + | BscBlockExecutionError::EthCallFailed + | BscBlockExecutionError::GetTopValidatorsFailed + | BscBlockExecutionError::ParentUnknown { .. } + | BscBlockExecutionError::ApplySnapshotFailed + | BscBlockExecutionError::UnknownHeader { .. } + | BscBlockExecutionError::VoteAddrNotFoundInSnap { .. } + | BscBlockExecutionError::BLSTInnerError + | BscBlockExecutionError::ProviderInnerError { .. } + | BscBlockExecutionError::SystemContractUpgradeError + | BscBlockExecutionError::FailedToSignSystemTransaction { .. } + | BscBlockExecutionError::GlobalSignerNotInitializedForMiningMode => { + // Note: Internal errors will be identified in the engine-tree, // and the entire program will exit. Self::other(err) } } } -} \ No newline at end of file +} diff --git a/src/node/evm/executor.rs b/src/node/evm/executor.rs index cf20de55..7bb210a0 100644 --- a/src/node/evm/executor.rs +++ b/src/node/evm/executor.rs @@ -1,15 +1,18 @@ +use super::config::BscBlockExecutionCtx; use super::patch::HertzPatchManager; +use crate::consensus::parlia::SnapshotProvider; use crate::{ consensus::{SYSTEM_ADDRESS, parlia::{Parlia, Snapshot, VoteAddress}}, evm::{precompiles, transaction::BscTxEnv}, hardforks::BscHardforks, metrics::{BscBlockchainMetrics, BscConsensusMetrics, BscExecutorMetrics, BscRewardsMetrics, BscVoteMetrics}, node::evm::config::BscExecutionSharedCtx, system_contracts::{ SystemContract, feynman_fork::ValidatorElectionInfo, get_upgrade_system_contracts, is_system_transaction } }; use alloy_consensus::{Header, Transaction, TxReceipt}; +use alloy_eips::eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}; use alloy_eips::{eip7685::Requests, Encodable2718}; use alloy_evm::{block::{ExecutableTx, StateChangeSource}, eth::receipt_builder::ReceiptBuilderCtx}; -use alloy_primitives::{hex, uint, Address, U256, BlockNumber, Bytes}; +use alloy_primitives::{hex, keccak256, uint, Address, U256, BlockNumber, Bytes}; use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks}; -use super::config::{BscBlockExecutionCtx, revm_spec_by_timestamp_and_block_number}; +use super::config::revm_spec_by_timestamp_and_block_number; use reth_evm::{ block::{BlockValidationError, CommitChanges}, eth::receipt_builder::ReceiptBuilder, @@ -29,11 +32,8 @@ use revm::{ state::Bytecode, DatabaseCommit, }; -use tracing::{error, warn, info, debug, trace}; -use alloy_eips::eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE}; -use alloy_primitives::keccak256; use std::{collections::HashMap, sync::Arc}; -use crate::consensus::parlia::SnapshotProvider; +use tracing::{debug, error, info, trace, warn}; /// Helper type for the input of post execution. #[allow(clippy::type_complexity)] #[derive(Debug, Clone)] @@ -42,7 +42,7 @@ pub(crate) struct InnerExecutionContext { pub(crate) expected_turn_length: Option, pub(crate) max_elected_validators: Option, pub(crate) validators_election_info: Option>, - pub(crate) snap: Option, + pub(crate) snap: Option>, pub(crate) header: Option
, pub(crate) parent_header: Option
, } @@ -121,7 +121,7 @@ where ) -> Self { let is_mainnet = spec.chain().id() == 56; // BSC mainnet chain ID let hertz_patch_manager = HertzPatchManager::new(is_mainnet); - + trace!("Succeed to new block executor, header: {:?}", ctx.header); if let Some(ref header) = ctx.header { crate::node::evm::util::HEADER_CACHE_READER @@ -181,7 +181,12 @@ where } /// Applies system contract upgrades if the Feynman fork is not yet active. - fn upgrade_contracts(&mut self, block_number: BlockNumber, block_timestamp: u64, parent_timestamp: u64) -> Result<(), BlockExecutionError> { + fn upgrade_contracts( + &mut self, + block_number: BlockNumber, + block_timestamp: u64, + parent_timestamp: u64, + ) -> Result<(), BlockExecutionError> { trace!( target: "bsc::executor::upgrade", block_number, @@ -189,7 +194,7 @@ where parent_timestamp, "Calling get_upgrade_system_contracts" ); - + let contracts = get_upgrade_system_contracts( &self.spec, block_number, @@ -215,7 +220,13 @@ where } /// Mimics Geth-BSC's TryUpdateBuildInSystemContract function - fn try_update_build_in_system_contract(&mut self, block_number: BlockNumber, block_timestamp: u64, parent_timestamp: u64, at_block_begin: bool) -> Result<(), BlockExecutionError> { + fn try_update_build_in_system_contract( + &mut self, + block_number: BlockNumber, + block_timestamp: u64, + parent_timestamp: u64, + at_block_begin: bool, + ) -> Result<(), BlockExecutionError> { if at_block_begin { // Upgrade system contracts before Feynman at block begin if !self.spec.is_feynman_active_at_timestamp(block_number, parent_timestamp) { @@ -227,10 +238,14 @@ where ); self.upgrade_contracts(block_number, block_timestamp, parent_timestamp)?; } - + // HistoryStorageAddress is a special system contract in BSC, which can't be upgraded // This must be done at block begin when Prague activates - if self.spec.is_prague_transition_at_block_and_timestamp(block_number, block_timestamp, parent_timestamp) { + if self.spec.is_prague_transition_at_block_and_timestamp( + block_number, + block_timestamp, + parent_timestamp, + ) { info!( target: "bsc::executor::prague", block_number, @@ -272,7 +287,7 @@ where beneficiary: Address, ) -> Result<(), BlockExecutionError> { let txs = self.system_contracts.genesis_contracts_txs(); - for tx in txs { + for tx in txs { self.transact_system_tx(tx.into(), beneficiary)?; } Ok(()) @@ -307,15 +322,16 @@ where "Deploying HistoryStorageAddress contract (Prague transition)" ); - let account = self.evm.db_mut().load_cache_account(HISTORY_STORAGE_ADDRESS).map_err(|err| { - error!( - target: "bsc::executor::prague", - block_number, - error = ?err, - "Failed to load HistoryStorageAddress account", - ); - BlockExecutionError::other(err) - })?; + let account = + self.evm.db_mut().load_cache_account(HISTORY_STORAGE_ADDRESS).map_err(|err| { + error!( + target: "bsc::executor::prague", + block_number, + error = ?err, + "Failed to load HistoryStorageAddress account", + ); + BlockExecutionError::other(err) + })?; let old_info = account.account_info(); debug!( @@ -334,7 +350,7 @@ where let transition = account.change(new_info, Default::default()); self.evm.db_mut().apply_transition(vec![(HISTORY_STORAGE_ADDRESS, transition)]); - + info!( target: "bsc::executor::prague", block_number, @@ -373,7 +389,7 @@ where is_miner = self.ctx.is_miner, "Start to apply_pre_execution_changes" ); - + // Update current block height and header height metrics let block_number = block_env.number().to::(); self.consensus_metrics.current_block_height.set(block_number as f64); @@ -384,7 +400,7 @@ where } else { self.check_new_block(&block_env)?; } - + // set state clear flag if the block is after the Spurious Dragon hardfork. let block_number = self.evm.block().number().to::(); let state_clear_flag = self.spec.is_spurious_dragon_active_at_block(block_number); @@ -396,7 +412,7 @@ where parent_timestamp, true )?; - + // Apply historical block hashes if Prague is active if self.spec.is_prague_active_at_block_and_timestamp( self.evm.block().number().to::(), @@ -644,7 +660,8 @@ where let mut temp_state = state.clone(); temp_state.remove(&SYSTEM_ADDRESS); - self.system_caller.on_state(StateChangeSource::Transaction(self.receipts.len()), &temp_state); + self.system_caller + .on_state(StateChangeSource::Transaction(self.receipts.len()), &temp_state); let gas_used = result.gas_used(); self.gas_used += gas_used; @@ -663,7 +680,6 @@ where Ok(gas_used) } - fn finish( mut self, ) -> Result<(Self::Evm, BlockExecutionResult), BlockExecutionError> { @@ -715,23 +731,25 @@ where // Update receipt height metric let block_number = self.evm.block().number().to::(); self.blockchain_metrics.current_receipt_height.set(block_number as f64); - + // Update block execution metrics self.executor_metrics.executed_blocks_total.increment(1); - + // Update block insert metrics // Calculate total transaction size in bytes (simplified estimation) - // Each receipt contributes approximately: + // Each receipt contributes approximately: // - Base tx overhead: ~100 bytes // - Per log: ~100 bytes (address + topics + data average) - let tx_size_bytes: usize = self.receipts.iter() + let tx_size_bytes: usize = self + .receipts + .iter() .map(|r| { let logs_count = r.logs().len(); 100 + logs_count * 100 // Base + logs estimation }) .sum(); self.blockchain_metrics.block_tx_size_bytes.set(tx_size_bytes as f64); - + // Calculate block receive time difference // This is the difference between current block timestamp and parent block timestamp let current_timestamp = self.evm.block().timestamp().to::(); @@ -740,7 +758,7 @@ where let time_diff = (current_timestamp as i64) - (parent_timestamp as i64); self.blockchain_metrics.block_receive_time_diff_seconds.set(time_diff as f64); } - + // Note: For gas-related metrics, use reth's ExecutorMetrics: // - sync.execution.gas_used_histogram // - sync.execution.gas_per_second (can be converted to MGas/s) diff --git a/src/node/evm/factory.rs b/src/node/evm/factory.rs index 72c687e6..f3a7df1e 100644 --- a/src/node/evm/factory.rs +++ b/src/node/evm/factory.rs @@ -6,9 +6,9 @@ use crate::{ hardforks::bsc::BscHardfork, }; use reth_evm::{precompiles::PrecompilesMap, Database, EvmEnv, EvmFactory}; +use revm::Inspector; use revm::context::{BlockEnv, result::{EVMError, HaltReason}}; use revm::inspector::NoOpInspector; -use reth_revm::Inspector; /// Factory producing [`BscEvm`]. #[derive(Debug, Default, Clone, Copy)] @@ -34,7 +34,7 @@ impl EvmFactory for BscEvmFactory { // CacheDB is used in trace scenarios where we need to replay transactions let type_name = std::any::type_name::(); let is_trace = type_name.contains("CacheDB"); - + BscEvm::new(input, db, NoOpInspector {}, false, is_trace) } diff --git a/src/node/evm/patch/mod.rs b/src/node/evm/patch/mod.rs index dd124557..f5b338fa 100644 --- a/src/node/evm/patch/mod.rs +++ b/src/node/evm/patch/mod.rs @@ -784,7 +784,11 @@ impl HertzPatchManager { Self { is_mainnet } } - pub fn patch_before_tx(&self, transaction: &T, state: &mut State) -> Result<(), BlockExecutionError> + pub fn patch_before_tx( + &self, + transaction: &T, + state: &mut State, + ) -> Result<(), BlockExecutionError> where T: SignedTransaction, DB: Database, @@ -797,9 +801,13 @@ impl HertzPatchManager { } Ok(()) } - + /// Apply patches after transaction execution - pub fn patch_after_tx(&self, transaction: &T, state: &mut State) -> Result<(), BlockExecutionError> + pub fn patch_after_tx( + &self, + transaction: &T, + state: &mut State, + ) -> Result<(), BlockExecutionError> where T: SignedTransaction, DB: Database, diff --git a/src/node/evm/post_execution.rs b/src/node/evm/post_execution.rs index 599b61d9..4b206710 100644 --- a/src/node/evm/post_execution.rs +++ b/src/node/evm/post_execution.rs @@ -1,5 +1,5 @@ -use super::executor::BscBlockExecutor; use super::error::{BscBlockExecutionError, BscBlockValidationError}; +use super::executor::BscBlockExecutor; use super::util::set_nonce; use super::config::revm_spec_by_timestamp_and_block_number; use crate::consensus::parlia::{FF_REWARD_DISTRIBUTION_INTERVAL}; @@ -49,7 +49,12 @@ where + FromTxWithEncoded, BlockEnv = BlockEnv, >, - Spec: EthereumHardforks + crate::hardforks::BscHardforks + EthChainSpec + Hardforks + Clone + 'static, + Spec: EthereumHardforks + + crate::hardforks::BscHardforks + + EthChainSpec + + Hardforks + + Clone + + 'static, R: ReceiptBuilder, ::Transaction: Unpin + From, ::Tx: FromTxWithEncoded<::Transaction>, @@ -59,8 +64,8 @@ where /// post check the new block, post check some parlia field and the system txs. /// depends on parlia, header and snapshot. pub(crate) fn post_check_new_block( - &mut self, - block: &BlockEnv + &mut self, + block: &BlockEnv, ) -> Result<(), BlockExecutionError> { tracing::debug!("Start to post check new block, block_number: {}, is_miner: {}", block.number(), self.ctx.is_miner); self.verify_validators(self.inner_ctx.current_validators.clone(), self.inner_ctx.header.clone())?; @@ -102,18 +107,24 @@ where let header_timestamp = self.evm.block().timestamp().to::(); let header_beneficiary = self.evm.block().beneficiary(); let parent_header = self.inner_ctx.parent_header.as_ref().unwrap().clone(); - if self.spec.is_feynman_active_at_timestamp(header_number, header_timestamp) && - is_breathe_block(parent_header.timestamp, header_timestamp) && - !self.spec.is_feynman_transition_at_timestamp(header_number, header_timestamp, parent_header.timestamp) + if self.spec.is_feynman_active_at_timestamp(header_number, header_timestamp) + && is_breathe_block(parent_header.timestamp, header_timestamp) + && !self.spec.is_feynman_transition_at_timestamp( + header_number, + header_timestamp, + parent_header.timestamp, + ) { - let max_elected_validators = self.inner_ctx.max_elected_validators.unwrap_or(U256::from(21)); - let validators_election_info = self.inner_ctx.validators_election_info.clone().unwrap_or_default(); - + let max_elected_validators = + self.inner_ctx.max_elected_validators.unwrap_or(U256::from(21)); + let validators_election_info = + self.inner_ctx.validators_election_info.clone().unwrap_or_default(); + self.update_validator_set_v2( - max_elected_validators, - validators_election_info.clone(), - header_beneficiary, - )?; + max_elected_validators, + validators_election_info.clone(), + header_beneficiary, + )?; tracing::debug!("Update validator set, block_number: {}, max_elected_validators: {}, validators_election_info: {:?}", header_number, max_elected_validators, validators_election_info); } @@ -127,36 +138,39 @@ where for tx in self.system_txs.iter() { tracing::error!("remaining system tx: {:?}", tx); } - return Err(BscBlockExecutionError::Validation(BscBlockValidationError::UnexpectedSystemTx).into()); + return Err(BscBlockExecutionError::Validation( + BscBlockValidationError::UnexpectedSystemTx, + ) + .into()); } let header = self.inner_ctx.header.as_ref().unwrap().clone(); - + // Notes: here we get the current block's snapshot (after applying this block's header) to prepare cache. // This is important because epoch_num may change during block application - let current_snap = self - .snapshot_provider - .as_ref() - .unwrap() - .snapshot_by_hash(&header.hash_slow()) - .ok_or(BlockExecutionError::msg("Failed to get current snapshot from snapshot provider"))?; - + let current_snap = + self.snapshot_provider.as_ref().unwrap().snapshot_by_hash(&header.hash_slow()).ok_or( + BlockExecutionError::msg("Failed to get current snapshot from snapshot provider"), + )?; + // Use epoch_num from current snapshot (after apply) for epoch boundary check let epoch_length = current_snap.epoch_num; let is_next_epoch = (header.number + 1).is_multiple_of(epoch_length); - if is_next_epoch { // cache validators + if is_next_epoch { + // cache validators // cache it on pre block. // for verify validators in post-check of fullnode mode and prepare new header in miner mode. self.get_current_validators_with_cache(header.number, header.hash_slow())?; } - { // cache turnlength + { + // cache turnlength let is_bohr = self.spec.is_bohr_active_at_timestamp(header.number, header.timestamp); tracing::debug!( "Check turn length cache update: block_number={}, epoch_length={}, is_next_epoch={}, is_bohr={}", header.number, epoch_length, is_next_epoch, is_bohr ); - + if is_next_epoch && is_bohr { let turn_length = self.get_turn_length(header.number, header.timestamp)?; let mut cache = TURN_LENGTH_CACHE.lock().unwrap(); @@ -170,19 +184,23 @@ where } fn verify_validators( - &mut self, - current_validators: Option<(Vec
, HashMap)>, - header: Option
+ &mut self, + current_validators: Option<(Vec
, HashMap)>, + header: Option
, ) -> Result<(), BlockExecutionError> { let header_ref = header.as_ref().unwrap(); let epoch_length = self.inner_ctx.snap.as_ref().unwrap().epoch_num; if !header_ref.number.is_multiple_of(epoch_length) { - tracing::trace!("Skip verify validator, block_number {} is not an epoch boundary, epoch_length: {}", header_ref.number, epoch_length); + tracing::trace!( + "Skip verify validator, block_number {} is not an epoch boundary, epoch_length: {}", + header_ref.number, + epoch_length + ); return Ok(()); } - let (mut validators, mut vote_addrs_map) = - current_validators.ok_or(BlockExecutionError::msg("Invalid current validators data"))?; + let (mut validators, mut vote_addrs_map) = current_validators + .ok_or(BlockExecutionError::msg("Invalid current validators data"))?; validators.sort(); let validator_num = validators.len(); @@ -205,24 +223,28 @@ where }) .collect(); - let expected = self.parlia.get_validator_bytes_from_header(header_ref, epoch_length).unwrap(); + let expected = + self.parlia.get_validator_bytes_from_header(header_ref, epoch_length).unwrap(); if !validator_bytes.as_slice().eq(expected.as_slice()) { warn!("validator bytes: {:?}", hex::encode(validator_bytes)); warn!("expected: {:?}", hex::encode(expected)); return Err(BlockExecutionError::msg("Invalid validators")); } - tracing::debug!("Succeed to verify validators, block_number: {}, epoch_length: {}", header_ref.number, epoch_length); + tracing::debug!( + "Succeed to verify validators, block_number: {}, epoch_length: {}", + header_ref.number, + epoch_length + ); Ok(()) } - fn verify_turn_length( - &mut self, - header: Option
- ) -> Result<(), BlockExecutionError> { + fn verify_turn_length(&mut self, header: Option
) -> Result<(), BlockExecutionError> { let header_ref = header.as_ref().unwrap(); let epoch_length = self.inner_ctx.snap.as_ref().unwrap().epoch_num; - if !header_ref.number.is_multiple_of(epoch_length) || !self.spec.is_bohr_active_at_timestamp(header_ref.number, header_ref.timestamp) { + if !header_ref.number.is_multiple_of(epoch_length) + || !self.spec.is_bohr_active_at_timestamp(header_ref.number, header_ref.timestamp) + { tracing::trace!("Skip verify turn length, block_number {} is not an epoch boundary, epoch_length: {}", header_ref.number, epoch_length); return Ok(()); } @@ -237,7 +259,7 @@ where let expected_turn_length = self.inner_ctx.expected_turn_length; if turn_length_matches(turn_length_from_header, expected_turn_length) { tracing::debug!("Succeed to verify turn length, block_number: {}", header_ref.number); - return Ok(()) + return Ok(()); } tracing::warn!( @@ -248,20 +270,22 @@ where epoch_length ); Err(BscBlockExecutionError::Validation( - BscBlockValidationError::MismatchingEpochTurnLengthError - ).into()) + BscBlockValidationError::MismatchingEpochTurnLengthError, + ) + .into()) } pub(crate) fn get_turn_length( &mut self, header_number: BlockNumber, - header_timestamp: u64 + header_timestamp: u64, ) -> Result { if self.spec.is_bohr_active_at_timestamp(header_number, header_timestamp) { let (to, data) = self.system_contracts.get_turn_length(); let bz = self.eth_call(to, data)?; - let turn_length = self.system_contracts.unpack_data_into_turn_length(bz.as_ref()).to::(); + let turn_length = + self.system_contracts.unpack_data_into_turn_length(bz.as_ref()).to::(); return Ok(turn_length); } @@ -271,28 +295,26 @@ where fn slash_spoiled_validator( &mut self, validator: Address, - spoiled_val: Address + spoiled_val: Address, ) -> Result<(), BlockExecutionError> { - self.transact_system_tx( - self.system_contracts.slash(spoiled_val), - validator, - )?; + self.transact_system_tx(self.system_contracts.slash(spoiled_val), validator)?; Ok(()) } pub(crate) fn transact_system_tx( - &mut self, - transaction: Transaction, - sender: Address + &mut self, + transaction: Transaction, + sender: Address, ) -> Result<(), BlockExecutionError> { // Record system contract call self.executor_metrics.system_contract_calls_total.increment(1); - + // Start timing for system contract duration let start_time = std::time::Instant::now(); - - let account = self.evm + + let account = self + .evm .db_mut() .basic(sender) .map_err(BlockExecutionError::other)? @@ -305,10 +327,9 @@ where if self.system_txs.is_empty() || hash != self.system_txs[0].signature_hash() { // slash tx could fail and not in the block if let Some(to) = transaction.to() { - if to == SLASH_CONTRACT && - (self.system_txs.is_empty() || - self.system_txs[0].to().unwrap_or_default() != - SLASH_CONTRACT) + if to == SLASH_CONTRACT + && (self.system_txs.is_empty() + || self.system_txs[0].to().unwrap_or_default() != SLASH_CONTRACT) { warn!("slash validator failed"); return Ok(()); @@ -320,8 +341,9 @@ where } self.executor_metrics.system_contract_errors_total.increment(1); return Err(BscBlockExecutionError::Validation( - BscBlockValidationError::UnexpectedSystemTx - ).into()); + BscBlockValidationError::UnexpectedSystemTx, + ) + .into()); } Some(self.system_txs.remove(0)) } else if is_signer_initialized() { @@ -330,7 +352,10 @@ where Err(e) => { tracing::warn!("Failed to sign system transaction: {}", e); self.executor_metrics.system_contract_errors_total.increment(1); - return Err(BscBlockExecutionError::FailedToSignSystemTransaction { error: e.to_string() }.into()); + return Err(BscBlockExecutionError::FailedToSignSystemTransaction { + error: e.to_string(), + } + .into()); } } } else { @@ -341,9 +366,10 @@ where if self.ctx.is_miner { if let Some(signed) = signed_tx.clone() { - let recovered = signed.clone().try_into_recovered_unchecked().unwrap_or_else(|_| { - panic!("Failed to recover system transaction signature") - }); + let recovered = signed + .clone() + .try_into_recovered_unchecked() + .unwrap_or_else(|_| panic!("Failed to recover system transaction signature")); self.shared_ctx.inner.borrow_mut().assembled_system_txs.push(recovered); if transaction.to() == Some(STAKE_HUB_CONTRACT) { @@ -418,11 +444,12 @@ where let ResultAndState { result, state } = result_and_state; let mut temp_state = state.clone(); temp_state.remove(&SYSTEM_ADDRESS); - self.system_caller.on_state(StateChangeSource::Transaction(self.receipts.len()), &temp_state); + self.system_caller + .on_state(StateChangeSource::Transaction(self.receipts.len()), &temp_state); let gas_used = result.gas_used(); self.gas_used += gas_used; - + // Record system transaction gas usage self.executor_metrics.system_tx_gas_used_total.increment(gas_used); @@ -442,18 +469,15 @@ where Ok(()) } - fn distribute_incoming( - &mut self, - validator: Address, - ) -> Result<(), BlockExecutionError> { + fn distribute_incoming(&mut self, validator: Address) -> Result<(), BlockExecutionError> { let system_account = self .evm .db_mut() .load_cache_account(SYSTEM_ADDRESS) .map_err(BlockExecutionError::other)?; - if system_account.account.is_none() || - system_account.account.as_ref().unwrap().info.balance == U256::ZERO + if system_account.account.is_none() + || system_account.account.as_ref().unwrap().info.balance == U256::ZERO { return Ok(()); } @@ -491,7 +515,9 @@ where // Track system rewards distribution self.rewards_metrics.system_rewards_distributed_total.increment(1); // Note: Truncating to u64 for metrics (large rewards unlikely) - self.rewards_metrics.system_rewards_amount_wei_total.increment(reward_to_system.min(u128::from(u64::MAX)) as u64); + self.rewards_metrics + .system_rewards_amount_wei_total + .increment(reward_to_system.min(u128::from(u64::MAX)) as u64); } block_reward -= reward_to_system; @@ -505,14 +531,14 @@ where // Track validator rewards distribution self.rewards_metrics.validator_rewards_distributed_total.increment(1); // Note: Truncating to u64 for metrics (large rewards unlikely) - self.rewards_metrics.validator_rewards_amount_wei_total.increment(block_reward.min(u128::from(u64::MAX)) as u64); - + self.rewards_metrics + .validator_rewards_amount_wei_total + .increment(block_reward.min(u128::from(u64::MAX)) as u64); + Ok(()) } - fn distribute_finality_reward( - &mut self, - ) -> Result<(), BlockExecutionError> { + fn distribute_finality_reward(&mut self) -> Result<(), BlockExecutionError> { // distribute finality reward per FF_REWARD_DISTRIBUTION_INTERVAL blocks. let block_number = self.evm.block().number().to::(); if !block_number.is_multiple_of(FF_REWARD_DISTRIBUTION_INTERVAL) { @@ -528,13 +554,15 @@ where // query block header and snapshot by hash from cache. let mut target_hash = self.ctx.base.parent_hash; for _ in (start..end).rev() { - let header = get_header_by_hash_from_cache(&target_hash). - ok_or_else(|| BlockExecutionError::msg(format!("Header not found for block hash: {target_hash}")))?; - let snap = self.snapshot_provider. - as_ref(). - unwrap(). - snapshot_by_hash(&header.parent_hash). - ok_or(BlockExecutionError::msg("Failed to get snapshot from snapshot provider"))?; + let header = get_header_by_hash_from_cache(&target_hash).ok_or_else(|| { + BlockExecutionError::msg(format!("Header not found for block hash: {target_hash}")) + })?; + let snap = self + .snapshot_provider + .as_ref() + .unwrap() + .snapshot_by_hash(&header.parent_hash) + .ok_or(BlockExecutionError::msg("Failed to get snapshot from snapshot provider"))?; if let Some(attestation) = self.parlia.get_vote_attestation_from_header(&header, snap.epoch_num).map_err(|err| { @@ -567,11 +595,22 @@ where accumulated_weights: &mut std::collections::HashMap, ) -> Result<(), BlockExecutionError> { let justified_header = get_header_by_hash_from_cache(&attestation.data.target_hash) - .ok_or_else(|| BlockExecutionError::msg(format!("Header not found, block_hash: {}", attestation.data.target_hash)))?; - let parent = get_header_by_hash_from_cache(&justified_header.parent_hash) - .ok_or_else(|| BlockExecutionError::msg(format!("Header not found, block_hash: {}", justified_header.parent_hash)))?; - let snapshot = self.snapshot_provider.as_ref().unwrap().snapshot_by_hash(&parent.hash_slow()); - let validators = &snapshot.unwrap().validators; + .ok_or_else(|| { + BlockExecutionError::msg(format!( + "Header not found, block_hash: {}", + attestation.data.target_hash + )) + })?; + let parent = + get_header_by_hash_from_cache(&justified_header.parent_hash).ok_or_else(|| { + BlockExecutionError::msg(format!( + "Header not found, block_hash: {}", + justified_header.parent_hash + )) + })?; + let snapshot = + self.snapshot_provider.as_ref().unwrap().snapshot_by_hash(&parent.hash_slow()); + let validators = &snapshot.unwrap().validators; let mut validators_bit_set = BitSet::new(); let vote_address_set = attestation.vote_address_set; for i in 0..64 { @@ -585,8 +624,9 @@ where BscBlockValidationError::InvalidAttestationVoteCount(GotExpected { got: validators_bit_set.len() as u64, expected: validators.len() as u64, - }) - ).into()); + }), + ) + .into()); } let mut valid_vote_count = 0; @@ -606,8 +646,7 @@ where } Ok(()) - - } + } fn update_validator_set_v2( &mut self, @@ -628,8 +667,8 @@ where /// generate system txs and apply them, used by miner. pub(crate) fn finalize_new_block( - &mut self, - block: &BlockEnv + &mut self, + block: &BlockEnv, ) -> Result<(), BlockExecutionError> { tracing::debug!("Start to finalize new block, block_number: {}, is_miner: {}", block.number(), self.ctx.is_miner); let snap = self.inner_ctx.snap.as_ref().unwrap(); @@ -670,44 +709,52 @@ where let header_timestamp = self.evm.block().timestamp().to::(); let header_beneficiary = self.evm.block().beneficiary(); let parent_header = self.inner_ctx.parent_header.as_ref().unwrap().clone(); - if self.spec.is_feynman_active_at_timestamp(header_number, header_timestamp) && - is_breathe_block(parent_header.timestamp, header_timestamp) && - !self.spec.is_feynman_transition_at_timestamp(header_number, header_timestamp, parent_header.timestamp) + if self.spec.is_feynman_active_at_timestamp(header_number, header_timestamp) + && is_breathe_block(parent_header.timestamp, header_timestamp) + && !self.spec.is_feynman_transition_at_timestamp( + header_number, + header_timestamp, + parent_header.timestamp, + ) { - let max_elected_validators = self.inner_ctx.max_elected_validators.unwrap_or(U256::from(21)); - let validators_election_info = self.inner_ctx.validators_election_info.clone().unwrap_or_default(); - + let max_elected_validators = + self.inner_ctx.max_elected_validators.unwrap_or(U256::from(21)); + let validators_election_info = + self.inner_ctx.validators_election_info.clone().unwrap_or_default(); + self.update_validator_set_v2( - max_elected_validators, - validators_election_info.clone(), - header_beneficiary, - )?; + max_elected_validators, + validators_election_info.clone(), + header_beneficiary, + )?; tracing::debug!("Update validator set, block_number: {}, max_elected_validators: {}, validators_election_info: {:?}", header_number, max_elected_validators, validators_election_info); } - // TODO: remove post cache later. // Use epoch_num from current snapshot (after apply) for epoch boundary check let is_next_epoch = (header_number + 1).is_multiple_of(epoch_length); - if is_next_epoch { + if is_next_epoch { // cache validators tracing::debug!( "Check validator cache update: block_number={}, epoch_length={}, is_next_epoch={}", - header_number, epoch_length, is_next_epoch + header_number, + epoch_length, + is_next_epoch ); let (validators, vote_addresses) = self.get_current_validators(header_number)?; - self.shared_ctx.inner.borrow_mut().current_validators = Some((validators, vote_addresses)); + self.shared_ctx.inner.borrow_mut().current_validators = + Some((validators, vote_addresses)); } - { + { // cache turnlength let is_bohr = self.spec.is_bohr_active_at_timestamp(header_number, header_timestamp); tracing::debug!( "Check turn length cache update: block_number={}, epoch_length={}, is_next_epoch={}, is_bohr={}", header_number, epoch_length, is_next_epoch, is_bohr ); - + if is_next_epoch && is_bohr { let turn_length = self.get_turn_length(header_number, header_timestamp)?; self.shared_ctx.inner.borrow_mut().turn_length = Some(turn_length); diff --git a/src/node/evm/pre_execution.rs b/src/node/evm/pre_execution.rs index f3a79b31..42cad96d 100644 --- a/src/node/evm/pre_execution.rs +++ b/src/node/evm/pre_execution.rs @@ -1,8 +1,26 @@ use super::executor::BscBlockExecutor; use crate::evm::transaction::BscTxEnv; +use crate::consensus::parlia::constants::K_ANCESTOR_GENERATION_DEPTH; +use crate::consensus::parlia::util::{debug_header, is_breathe_block}; +use crate::consensus::parlia::vote::MAX_ATTESTATION_EXTRA_LENGTH; +use crate::consensus::parlia::{Snapshot, VoteAddress, DIFF_INTURN, DIFF_NOTURN}; +use crate::node::evm::error::{BscBlockExecutionError, BscBlockValidationError}; +use crate::node::evm::util::HEADER_CACHE_READER; +use crate::system_contracts::feynman_fork::ValidatorElectionInfo; +use alloy_consensus::{BlockHeader, Header, TxReceipt}; +use alloy_primitives::{BlockHash, BlockNumber, B256}; +use bit_set::BitSet; +use blst::{ + min_pk::{PublicKey, Signature}, + BLST_ERROR, +}; use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks}; -use reth_evm::{eth::receipt_builder::ReceiptBuilder, execute::BlockExecutionError, Database, Evm, FromRecoveredTx, FromTxWithEncoded, IntoTxEnv}; +use reth_evm::{ + eth::receipt_builder::ReceiptBuilder, execute::BlockExecutionError, Database, Evm, + FromRecoveredTx, FromTxWithEncoded, IntoTxEnv, +}; +use reth_primitives::GotExpected; use reth_primitives::TransactionSigned; use reth_revm::State; use revm::{ @@ -10,36 +28,23 @@ use revm::{ context_interface::block::Block, primitives::{Address, Bytes, TxKind, U256}, }; -use alloy_consensus::{TxReceipt, Header, BlockHeader}; -use alloy_primitives::{BlockHash, BlockNumber, B256}; -use crate::consensus::parlia::{VoteAddress, Snapshot, DIFF_INTURN, DIFF_NOTURN}; -use crate::consensus::parlia::util::{is_breathe_block, debug_header}; -use crate::consensus::parlia::vote::MAX_ATTESTATION_EXTRA_LENGTH; -use crate::node::evm::error::{BscBlockExecutionError, BscBlockValidationError}; -use crate::node::evm::util::HEADER_CACHE_READER; -use crate::system_contracts::feynman_fork::ValidatorElectionInfo; -use std::{collections::HashMap, sync::{LazyLock, Mutex}}; +use std::sync::Arc; use schnellru::{ByLength, LruMap}; -use reth_primitives::GotExpected; -use blst::{ - min_pk::{PublicKey, Signature}, - BLST_ERROR, +use std::{ + collections::HashMap, + sync::{LazyLock, Mutex}, }; -use bit_set::BitSet; -use crate::consensus::parlia::constants::K_ANCESTOR_GENERATION_DEPTH; const BLST_DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; type ValidatorCache = LruMap, Vec), ByLength>; type TurnLengthCache = LruMap; -pub static VALIDATOR_CACHE: LazyLock> = LazyLock::new(|| { - Mutex::new(LruMap::new(ByLength::new(1024))) -}); +pub static VALIDATOR_CACHE: LazyLock> = + LazyLock::new(|| Mutex::new(LruMap::new(ByLength::new(1024)))); -pub static TURN_LENGTH_CACHE: LazyLock> = LazyLock::new(|| { - Mutex::new(LruMap::new(ByLength::new(1024))) -}); +pub static TURN_LENGTH_CACHE: LazyLock> = + LazyLock::new(|| Mutex::new(LruMap::new(ByLength::new(1024)))); impl<'a, DB, EVM, Spec, R: ReceiptBuilder> BscBlockExecutor<'a, EVM, Spec, R> where @@ -51,7 +56,12 @@ where + FromTxWithEncoded, BlockEnv = BlockEnv, >, - Spec: EthereumHardforks + crate::hardforks::BscHardforks + EthChainSpec + Hardforks + Clone + 'static, + Spec: EthereumHardforks + + crate::hardforks::BscHardforks + + EthChainSpec + + Hardforks + + Clone + + 'static, R: ReceiptBuilder, ::Transaction: Unpin + From, ::Tx: FromTxWithEncoded<::Transaction>, @@ -74,7 +84,9 @@ where .lock() .unwrap() .get_header_by_hash(&header.parent_hash) - .ok_or(BlockExecutionError::msg("Failed to get parent header from global header reader"))?; + .ok_or(BlockExecutionError::msg( + "Failed to get parent header from global header reader", + ))?; self.inner_ctx.parent_header = Some(parent_header.clone()); let snap = self @@ -83,7 +95,7 @@ where .unwrap() .snapshot_by_hash(&header.parent_hash) .ok_or(BlockExecutionError::msg("Failed to get snapshot from snapshot provider"))?; - self.inner_ctx.snap = Some(snap.clone()); + self.inner_ctx.snap = Some(Arc::new(snap.clone())); self.inner_ctx.expected_turn_length = None; self.verify_cascading_fields(&header, &parent_header, &snap)?; @@ -91,9 +103,14 @@ where let epoch_length = snap.epoch_num; if header.number.is_multiple_of(epoch_length) { // TODO: need fix it later, it may got error when restart the node? - let (validator_set, vote_addresses) = self.get_current_validators_with_cache(header.number-1, header.parent_hash)?; - tracing::debug!("validator_set: {:?}, vote_addresses: {:?}", validator_set, vote_addresses); - + let (validator_set, vote_addresses) = + self.get_current_validators_with_cache(header.number - 1, header.parent_hash)?; + tracing::debug!( + "validator_set: {:?}, vote_addresses: {:?}", + validator_set, + vote_addresses + ); + let vote_addrs_map = if vote_addresses.is_empty() { HashMap::new() } else { @@ -116,24 +133,36 @@ where // Also fetch on-chain NodeIDs for validators (EVN identification) and update cache. // Only available after Maxwell hardfork when StakeHub contract's getNodeIDs is deployed if self.spec.is_maxwell_active_at_timestamp(header.number, header.timestamp) { - let (to2, data2) = self.system_contracts.get_node_ids(self.inner_ctx.current_validators.as_ref().unwrap().0.clone()); + let (to2, data2) = self + .system_contracts + .get_node_ids(self.inner_ctx.current_validators.as_ref().unwrap().0.clone()); if let Ok(output2) = self.eth_call(to2, data2) { - let (_consensus_addrs, node_ids_list) = self.system_contracts.unpack_data_into_node_ids(&output2); + let (_consensus_addrs, node_ids_list) = + self.system_contracts.unpack_data_into_node_ids(&output2); tracing::debug!("node_ids_list: {:?}", node_ids_list); let mut flat: Vec<[u8; 32]> = Vec::new(); - for ids in node_ids_list { for id in ids { flat.push(id); } } + for ids in node_ids_list { + for id in ids { + flat.push(id); + } + } crate::node::network::evn_peers::update_onchain_nodeids(flat); } } } - - if self.spec.is_feynman_active_at_timestamp(header.number, header.timestamp) && - !self.spec.is_feynman_transition_at_timestamp(header.number, header.timestamp, parent_header.timestamp) && - is_breathe_block(parent_header.timestamp, header.timestamp) + + if self.spec.is_feynman_active_at_timestamp(header.number, header.timestamp) + && !self.spec.is_feynman_transition_at_timestamp( + header.number, + header.timestamp, + parent_header.timestamp, + ) + && is_breathe_block(parent_header.timestamp, header.timestamp) { let (to, data) = self.system_contracts.get_max_elected_validators(); let bz = self.eth_call(to, data)?; - let max_elected_validators = self.system_contracts.unpack_data_into_max_elected_validators(bz.as_ref()); + let max_elected_validators = + self.system_contracts.unpack_data_into_max_elected_validators(bz.as_ref()); tracing::debug!("max_elected_validators: {:?}", max_elected_validators); self.inner_ctx.max_elected_validators = Some(max_elected_validators); @@ -144,9 +173,9 @@ where self.system_contracts.unpack_data_into_validator_election_info(bz.as_ref()); let total_length = total_length.to::() as usize; - if validators.len() != total_length || - voting_powers.len() != total_length || - vote_addrs.len() != total_length + if validators.len() != total_length + || voting_powers.len() != total_length + || vote_addrs.len() != total_length { return Err(BlockExecutionError::msg("Failed to get top validators")); } @@ -169,9 +198,9 @@ where } pub(crate) fn get_current_validators_with_cache( - &mut self, + &mut self, block_number: BlockNumber, - block_hash: BlockHash + block_hash: BlockHash, ) -> Result<(Vec
, Vec), BlockExecutionError> { { let mut cache = VALIDATOR_CACHE.lock().unwrap(); @@ -194,7 +223,6 @@ where Ok(result) } - pub(crate) fn eth_call( &mut self, to: Address, @@ -237,29 +265,33 @@ where tracing::error!("Failed to eth call, to: {:?}, data: {:?}", to, data); return Err(BlockExecutionError::msg("ETH call failed")); } - let output = result_and_state.result.output().ok_or(BlockExecutionError::msg("ETH call output is None"))?; + let output = result_and_state + .result + .output() + .ok_or(BlockExecutionError::msg("ETH call output is None"))?; Ok(output.clone()) } pub(crate) fn get_current_validators( - &mut self, - block_number: BlockNumber + &mut self, + block_number: BlockNumber, ) -> Result<(Vec
, Vec), BlockExecutionError> { - let result = if self.spec.is_luban_active_at_block(block_number) { let (to, data) = self.system_contracts.get_current_validators(); let output = self.eth_call(to, data)?; self.system_contracts.unpack_data_into_validator_set(&output) } else { - let (to, data) = self.system_contracts.get_current_validators_before_luban(block_number); + let (to, data) = + self.system_contracts.get_current_validators_before_luban(block_number); let output = self.eth_call(to, data)?; - let validator_set = self.system_contracts.unpack_data_into_validator_set_before_luban(&output); + let validator_set = + self.system_contracts.unpack_data_into_validator_set_before_luban(&output); (validator_set, Vec::new()) }; Ok(result) } - + fn verify_cascading_fields( &self, header: &Header, @@ -267,14 +299,14 @@ where snap: &Snapshot, ) -> Result<(), BlockExecutionError> { self.verify_block_time_for_ramanujan(snap, header, parent)?; - + // Verify vote attestation and track errors if let Err(err) = self.verify_vote_attestation(snap, header, parent) { // Update vote attestation error metric for all attestation-related errors self.vote_metrics.vote_attestation_errors_total.increment(1); return Err(err); } - + self.verify_seal(snap, header)?; Ok(()) @@ -299,26 +331,36 @@ where return Ok(()); } - let attestation = - self.parlia.get_vote_attestation_from_header(header, snap.epoch_num).map_err(|err| { - tracing::error!("Failed to get vote attestation from header, block_number: {}, error: {:?}", header.number(), err); - BscBlockExecutionError::Validation(BscBlockValidationError::ParliaConsensusError { error: err.into() }) + let attestation = self + .parlia + .get_vote_attestation_from_header(header, snap.epoch_num) + .map_err(|err| { + tracing::error!( + "Failed to get vote attestation from header, block_number: {}, error: {:?}", + header.number(), + err + ); + BscBlockExecutionError::Validation(BscBlockValidationError::ParliaConsensusError { + error: err.into(), + }) })?; if let Some(attestation) = attestation { if attestation.extra.len() > MAX_ATTESTATION_EXTRA_LENGTH { return Err(BscBlockExecutionError::Validation( BscBlockValidationError::TooLargeAttestationExtraLen { extra_len: MAX_ATTESTATION_EXTRA_LENGTH, - } - ).into()); + }, + ) + .into()); } - + // the attestation target block should be direct parent. let target_block = attestation.data.target_number; let target_hash = attestation.data.target_hash; let mut is_match = false; let mut ancestor = parent.clone(); - let depth = if self.spec.is_fermi_active_at_timestamp(header.number(), header.timestamp) { + let depth = if self.spec.is_fermi_active_at_timestamp(header.number(), header.timestamp) + { K_ANCESTOR_GENERATION_DEPTH } else { 1 @@ -332,33 +374,49 @@ where .lock() .unwrap() .get_header_by_hash(&ancestor.parent_hash()) - .ok_or_else(|| BscBlockExecutionError::UnknownHeader { block_hash: ancestor.parent_hash() })?; + .ok_or_else(|| BscBlockExecutionError::UnknownHeader { + block_hash: ancestor.parent_hash(), + })?; tracing::debug!("ancestor: {:?}", ancestor); } if !is_match { return Err(BscBlockExecutionError::Validation( BscBlockValidationError::InvalidAttestationTarget { - block_number: GotExpected { got: target_block, expected: ancestor.number() }, - block_hash: GotExpected { got: target_hash, expected: ancestor.hash_slow() } - .into(), - } - ).into()); + block_number: GotExpected { + got: target_block, + expected: ancestor.number(), + }, + block_hash: GotExpected { + got: target_hash, + expected: ancestor.hash_slow(), + } + .into(), + }, + ) + .into()); } - + // the attestation source block should be the highest justified block. let source_block = attestation.data.source_number; let source_hash = attestation.data.source_hash; - + let justified = self.get_justified_header(snap)?; if source_block != justified.number() || source_hash != justified.hash_slow() { return Err(BscBlockExecutionError::Validation( BscBlockValidationError::InvalidAttestationSource { - block_number: GotExpected { got: source_block, expected: justified.number() }, - block_hash: GotExpected { got: source_hash, expected: justified.hash_slow() } - .into(), - } - ).into()); + block_number: GotExpected { + got: source_block, + expected: justified.number(), + }, + block_hash: GotExpected { + got: source_hash, + expected: justified.hash_slow(), + } + .into(), + }, + ) + .into()); } let pre_snap = self @@ -366,12 +424,14 @@ where .as_ref() .unwrap() .snapshot_by_hash(&ancestor.parent_hash) - .ok_or(BlockExecutionError::msg("Failed to get pre snapshot from snapshot provider"))?; + .ok_or(BlockExecutionError::msg( + "Failed to get pre snapshot from snapshot provider", + ))?; // query bls keys from snapshot. let validators_count = pre_snap.validators.len(); let vote_bit_set: BitSet = BitSet::from_iter( - (0..64).filter(|&i| (attestation.vote_address_set >> i) & 1 != 0) + (0..64).filter(|&i| (attestation.vote_address_set >> i) & 1 != 0), ); let bit_set_count = vote_bit_set.len(); if bit_set_count > validators_count { @@ -379,10 +439,11 @@ where BscBlockValidationError::InvalidAttestationVoteCount(GotExpected { got: bit_set_count as u64, expected: validators_count as u64, - }) - ).into()); + }), + ) + .into()); } - + let mut vote_addrs: Vec = Vec::with_capacity(bit_set_count); for (i, val) in pre_snap.validators.iter().enumerate() { if !vote_bit_set.contains(i) { @@ -403,99 +464,113 @@ where BscBlockValidationError::InvalidAttestationVoteCount(GotExpected { got: vote_addrs.len() as u64, expected: at_least_votes as u64, - }) - ).into()); + }), + ) + .into()); } - + // check bls aggregate sig let mut pubkeys: Vec = Vec::with_capacity(vote_addrs.len()); for addr in &vote_addrs { match PublicKey::from_bytes(addr.as_slice()) { Ok(pk) => pubkeys.push(pk), Err(_) => { - return Err( - BscBlockExecutionError::Validation( - BscBlockValidationError::InvalidAttestationSignature - ).into() - ); + return Err(BscBlockExecutionError::Validation( + BscBlockValidationError::InvalidAttestationSignature, + ) + .into()); } } } let vote_addrs_ref: Vec<&PublicKey> = pubkeys.iter().collect(); - + let sig = Signature::from_bytes(&attestation.agg_signature[..]).map_err(|_| { - BscBlockExecutionError::Validation(BscBlockValidationError::InvalidAttestationSignature) + BscBlockExecutionError::Validation( + BscBlockValidationError::InvalidAttestationSignature, + ) })?; - + // Track BLS verification attempt self.vote_metrics.bls_verifications_total.increment(1); let start = std::time::Instant::now(); - + let err = sig.fast_aggregate_verify( true, attestation.data.hash().as_slice(), BLST_DST, &vote_addrs_ref, ); - + // Record verification duration - self.vote_metrics.bls_verification_duration_seconds.record(start.elapsed().as_secs_f64()); - + self.vote_metrics + .bls_verification_duration_seconds + .record(start.elapsed().as_secs_f64()); + return match err { BLST_ERROR::BLST_SUCCESS => Ok(()), _ => { // Update BLS verification failure metric (kept here as it's a specific metric) self.vote_metrics.bls_verification_failures_total.increment(1); Err(BscBlockExecutionError::Validation( - BscBlockValidationError::InvalidAttestationSignature - ).into()) - }, + BscBlockValidationError::InvalidAttestationSignature, + ) + .into()) + } }; } - + Ok(()) } - - fn verify_seal( - &self, - snap: &Snapshot, - header: &Header, - ) -> Result<(), BlockExecutionError> { + + fn verify_seal(&self, snap: &Snapshot, header: &Header) -> Result<(), BlockExecutionError> { let proposer = self.parlia.recover_proposer(header).map_err(|err| { - tracing::error!("Failed to recover proposer from header, block_number: {}, error: {:?}", header.number(), err); - BscBlockExecutionError::Validation(BscBlockValidationError::ParliaConsensusError { error: err.into() }) + tracing::error!( + "Failed to recover proposer from header, block_number: {}, error: {:?}", + header.number(), + err + ); + BscBlockExecutionError::Validation(BscBlockValidationError::ParliaConsensusError { + error: err.into(), + }) })?; if proposer != header.beneficiary { - tracing::error!("Wrong header signer, block_number: {}, proposer: {:?}, expected: {:?}", - header.number(), proposer, header.beneficiary); + tracing::error!( + "Wrong header signer, block_number: {}, proposer: {:?}, expected: {:?}", + header.number(), + proposer, + header.beneficiary + ); debug_header(header, self.spec.chain().id(), "verify_seal_header"); return Err(BscBlockExecutionError::Validation( BscBlockValidationError::WrongHeaderSigner { block_number: header.number(), signer: GotExpected { got: proposer, expected: header.beneficiary }.into(), - } - ).into()); + }, + ) + .into()); } if !snap.validators.contains(&proposer) { return Err(BscBlockExecutionError::Validation( - BscBlockValidationError::SignerUnauthorized { - block_number: header.number(), - proposer - } - ).into()); + BscBlockValidationError::SignerUnauthorized { + block_number: header.number(), + proposer, + }, + ) + .into()); } if snap.sign_recently(proposer) { return Err(BscBlockExecutionError::Validation( - BscBlockValidationError::SignerOverLimit { proposer } - ).into()); + BscBlockValidationError::SignerOverLimit { proposer }, + ) + .into()); } let is_inturn = snap.is_inturn(proposer); - if (is_inturn && header.difficulty != DIFF_INTURN) || - (!is_inturn && header.difficulty != DIFF_NOTURN) + if (is_inturn && header.difficulty != DIFF_INTURN) + || (!is_inturn && header.difficulty != DIFF_NOTURN) { let expected_difficulty = if is_inturn { DIFF_INTURN } else { DIFF_NOTURN }; tracing::warn!( @@ -511,8 +586,9 @@ where "Block difficulty validation failed: mismatch between inturn status and difficulty" ); return Err(BscBlockExecutionError::Validation( - BscBlockValidationError::InvalidDifficulty { difficulty: header.difficulty } - ).into()); + BscBlockValidationError::InvalidDifficulty { difficulty: header.difficulty }, + ) + .into()); } Ok(()) @@ -523,13 +599,9 @@ where snap: &Snapshot, ) -> Result { if snap.vote_data.source_hash == B256::ZERO && snap.vote_data.target_hash == B256::ZERO { - return HEADER_CACHE_READER - .lock() - .unwrap() - .get_header_by_number(0) - .ok_or_else(|| { - BscBlockExecutionError::UnknownHeader { block_hash: B256::ZERO }.into() - }); + return HEADER_CACHE_READER.lock().unwrap().get_header_by_number(0).ok_or_else(|| { + BscBlockExecutionError::UnknownHeader { block_hash: B256::ZERO }.into() + }); } HEADER_CACHE_READER @@ -537,20 +609,23 @@ where .unwrap() .get_header_by_hash(&snap.vote_data.target_hash) .ok_or_else(|| { - BscBlockExecutionError::UnknownHeader { block_hash: snap.vote_data.target_hash }.into() + BscBlockExecutionError::UnknownHeader { block_hash: snap.vote_data.target_hash } + .into() }) } /// prepare some intermediate data for produce new block. pub(crate) fn prepare_new_block( - &mut self, - block: &BlockEnv + &mut self, + block: &BlockEnv, ) -> Result<(), BlockExecutionError> { let parent_header = crate::node::evm::util::HEADER_CACHE_READER .lock() .unwrap() .get_header_by_hash(&self.ctx.base.parent_hash) - .ok_or(BlockExecutionError::msg("Failed to get parent header from global header reader"))?; + .ok_or(BlockExecutionError::msg( + "Failed to get parent header from global header reader", + ))?; self.inner_ctx.parent_header = Some(parent_header.clone()); let snap = self .snapshot_provider @@ -558,7 +633,7 @@ where .unwrap() .snapshot_by_hash(&self.ctx.base.parent_hash) .ok_or(BlockExecutionError::msg("Failed to get snapshot from snapshot provider"))?; - self.inner_ctx.snap = Some(snap.clone()); + self.inner_ctx.snap = Some(Arc::new(snap.clone())); let header_number = block.number().to::(); let header_timestamp = block.timestamp().to::(); @@ -568,7 +643,8 @@ where { let (to, data) = self.system_contracts.get_max_elected_validators(); let bz = self.eth_call(to, data)?; - let max_elected_validators = self.system_contracts.unpack_data_into_max_elected_validators(bz.as_ref()); + let max_elected_validators = + self.system_contracts.unpack_data_into_max_elected_validators(bz.as_ref()); tracing::debug!("max_elected_validators: {:?}", max_elected_validators); self.inner_ctx.max_elected_validators = Some(max_elected_validators); @@ -579,9 +655,9 @@ where self.system_contracts.unpack_data_into_validator_election_info(bz.as_ref()); let total_length = total_length.to::() as usize; - if validators.len() != total_length || - voting_powers.len() != total_length || - vote_addrs.len() != total_length + if validators.len() != total_length + || voting_powers.len() != total_length + || vote_addrs.len() != total_length { return Err(BlockExecutionError::msg("Failed to get top validators")); } diff --git a/src/node/evm/util.rs b/src/node/evm/util.rs index b3c4cb34..ff843d2d 100644 --- a/src/node/evm/util.rs +++ b/src/node/evm/util.rs @@ -1,6 +1,6 @@ +use alloy_consensus::{BlockHeader, Header}; +use alloy_primitives::{BlockHash, BlockNumber, B256}; use reth_primitives::Transaction; -use alloy_consensus::{Header, BlockHeader}; -use alloy_primitives::{B256, BlockHash, BlockNumber}; use schnellru::{ByLength, LruMap}; use std::sync::{LazyLock, Mutex}; @@ -9,23 +9,23 @@ pub fn set_nonce(transaction: Transaction, nonce: u64) -> Transaction { Transaction::Legacy(mut tx) => { tx.nonce = nonce; Transaction::Legacy(tx) - }, + } Transaction::Eip2930(mut tx) => { tx.nonce = nonce; Transaction::Eip2930(tx) - }, + } Transaction::Eip1559(mut tx) => { tx.nonce = nonce; Transaction::Eip1559(tx) - }, + } Transaction::Eip4844(mut tx) => { tx.nonce = nonce; Transaction::Eip4844(tx) - }, + } Transaction::Eip7702(mut tx) => { tx.nonce = nonce; Transaction::Eip7702(tx) - }, + } } } @@ -49,12 +49,17 @@ impl HeaderCacheReader { tracing::trace!("Get header from cache, block_number: {:?}", header.number()); return Some(header.clone()); } - if let Some(header) = crate::shared::get_canonical_header_by_number_from_provider(block_number) { + if let Some(header) = + crate::shared::get_canonical_header_by_number_from_provider(block_number) + { tracing::trace!("Get header from provider, block_number: {:?}", header.number()); return Some(header); } - tracing::warn!("Failed to get header from cache and provider, block_number: {:?}", block_number); + tracing::warn!( + "Failed to get header from cache and provider, block_number: {:?}", + block_number + ); None } @@ -62,7 +67,8 @@ impl HeaderCacheReader { if let Some(header) = self.blockhash_to_header.get(block_hash) { return Some(header.clone()); } - if let Some(header) = crate::shared::get_canonical_header_by_hash_from_provider(block_hash) { + if let Some(header) = crate::shared::get_canonical_header_by_hash_from_provider(block_hash) + { return Some(header); } None @@ -78,26 +84,37 @@ impl HeaderCacheReader { let header_clone_for_log = header.clone(); self.blocknumber_to_header.insert(block_number, header.clone()); self.blockhash_to_header.insert(block_hash, header); - tracing::trace!("Insert header to cache, block_number: {:?}, block_hash: {:?}, header: {:?}", block_number, block_hash, header_clone_for_log); + tracing::trace!( + "Insert header to cache, block_number: {:?}, block_hash: {:?}, header: {:?}", + block_number, + block_hash, + header_clone_for_log + ); } } -pub static HEADER_CACHE_READER: LazyLock> = LazyLock::new(|| { - Mutex::new(HeaderCacheReader::new(100000)) -}); - +pub static HEADER_CACHE_READER: LazyLock> = + LazyLock::new(|| Mutex::new(HeaderCacheReader::new(100000))); /// Get header by hash from the global header provider pub fn get_header_by_hash_from_cache(block_hash: &BlockHash) -> Option
{ let header = HEADER_CACHE_READER.lock().unwrap().get_header_by_hash(block_hash); - tracing::trace!("Succeed to fetch header by hash, is_none: {} for hash {}", header.is_none(), block_hash); + tracing::trace!( + "Succeed to fetch header by hash, is_none: {} for hash {}", + header.is_none(), + block_hash + ); header } /// Get canonical header by number from the global header provider pub fn get_cannonical_header_from_cache(number: BlockNumber) -> Option
{ let header = HEADER_CACHE_READER.lock().unwrap().get_header_by_number(number); - tracing::debug!("Succeed to fetch canonical header by number, is_none: {} for number {}", header.is_none(), number); + tracing::debug!( + "Succeed to fetch canonical header by number, is_none: {} for number {}", + header.is_none(), + number + ); header } diff --git a/src/node/miner/bid_simulator.rs b/src/node/miner/bid_simulator.rs index 5037020c..1d1c7a53 100644 --- a/src/node/miner/bid_simulator.rs +++ b/src/node/miner/bid_simulator.rs @@ -1,7 +1,7 @@ use crate::chainspec::BscChainSpec; use crate::consensus::eip4844::{calc_blob_fee, is_blob_eligible_block}; -use crate::consensus::parlia::provider::SnapshotProvider; use crate::consensus::parlia::Snapshot; +use crate::consensus::parlia::provider::SnapshotProvider; use crate::hardforks::BscHardforks; use crate::node::engine::BscBuiltPayload; use crate::node::evm::config::{BscEvmConfig, BscNextBlockEnvAttributes, ValidatorCacheSink}; @@ -14,6 +14,7 @@ use alloy_consensus::Transaction; use alloy_evm::Evm; use alloy_primitives::U256; use alloy_primitives::{Address, B256}; +use either::Either; use parking_lot::RwLock; use reth::payload::EthPayloadBuilderAttributes; use reth::transaction_pool::BestTransactionsAttributes; @@ -26,7 +27,6 @@ use reth_evm::{ConfigureEvm, NextBlockEnvAttributes}; use reth_execution_types::BlockExecutionOutput; use reth_payload_primitives::PayloadBuilderAttributes; use reth_payload_primitives::{BuiltPayloadExecutedBlock, PayloadBuilderError}; -use either::Either; use revm_context_interface::Block as EvmBlock; use reth_primitives::SealedHeader; use reth_primitives::TransactionSigned; @@ -243,7 +243,10 @@ where } else if !best_bid.is_committed() { _bid_runtime = best_bid_runtime; _bid_accepted = false; - debug!("discard new bid and to simulate the non-committed bestBidToRun builder:{}, bid_hash:{}", _bid_runtime.bid.builder,""); + debug!( + "discard new bid and to simulate the non-committed bestBidToRun builder:{}, bid_hash:{}", + _bid_runtime.bid.builder, "" + ); } else { to_commit = false; _bid_accepted = false; @@ -271,7 +274,10 @@ where let bid_simulate_req = self.commit_bid(5, _bid_runtime); return Some(bid_simulate_req); } else { - debug!("simulate in progress, no interrupt after delay_ms:{}, NO_INTERRUPT_LEFT_OVER:{},bid hash:{}", delay_ms, NO_INTERRUPT_LEFT_OVER, _bid_runtime.bid.bid_hash); + debug!( + "simulate in progress, no interrupt after delay_ms:{}, NO_INTERRUPT_LEFT_OVER:{},bid hash:{}", + delay_ms, NO_INTERRUPT_LEFT_OVER, _bid_runtime.bid.bid_hash + ); } } else { let bid_simulate_req = self.commit_bid(5, _bid_runtime); @@ -327,7 +333,10 @@ where expected_block_reward * U256::from(_validator_commission); expected_validator_reward /= U256::from(10000u64); if expected_validator_reward < _bid.builder_fee { - debug!("BidSimulator: invalid bid, builder fee exceeds validator reward, ignore expected_validator_reward:{} builder_fee:{}", expected_validator_reward, _bid.builder_fee); + debug!( + "BidSimulator: invalid bid, builder fee exceeds validator reward, ignore expected_validator_reward:{} builder_fee:{}", + expected_validator_reward, _bid.builder_fee + ); return Err("invalid bid: builder fee exceeds validator reward".into()); } expected_validator_reward -= _bid.builder_fee; @@ -577,9 +586,7 @@ where if !receipt.success && bid_runtime.un_revertible_set.contains(&tx_hash) { debug!( "bidSimulator: un_revertible transaction failed, rejecting bid. tx_hash: {:?}, bid_hash: {:?}, block_number: {}", - tx_hash, - bid_runtime.bid.bid_hash, - bid_runtime.bid.block_number + tx_hash, bid_runtime.bid.bid_hash, bid_runtime.bid.block_number ); return; } @@ -596,7 +603,8 @@ where sealed_block = Arc::new(plain.into()); let requests = execution_result.requests.clone(); - let execution_outcome = BlockExecutionOutput { state: db.take_bundle(), result: execution_result }; + let execution_outcome = + BlockExecutionOutput { state: db.take_bundle(), result: execution_result }; let executed: BuiltPayloadExecutedBlock<_> = BuiltPayloadExecutedBlock { recovered_block: Arc::new(block.clone()), execution_output: Arc::new(execution_outcome), @@ -664,14 +672,15 @@ where self.mev_metrics.invalid_bids_total.increment(1); } - debug!("bidSimulator: sim_bid finished, block number:{}, parent hash:{}, builder:{}, bid hash:{}, gas used:{}, gas fee:{}, success:{}", - bid_runtime.bid.block_number, - bid_runtime.bid.parent_hash, - bid_runtime.bid.builder, - bid_runtime.bid.bid_hash, - bid_runtime.gas_used, - bid_runtime.gas_fee, - success, + debug!( + "bidSimulator: sim_bid finished, block number:{}, parent hash:{}, builder:{}, bid hash:{}, gas used:{}, gas fee:{}, success:{}", + bid_runtime.bid.block_number, + bid_runtime.bid.parent_hash, + bid_runtime.bid.builder, + bid_runtime.bid.bid_hash, + bid_runtime.gas_used, + bid_runtime.gas_fee, + success, ); self.simulating_bid.write().remove(&parent_hash); @@ -722,10 +731,10 @@ where + 'static, EvmConfig: ConfigureEvm + 'static, ::Primitives: reth_primitives_traits::NodePrimitives< - BlockHeader = alloy_consensus::Header, - SignedTx = alloy_consensus::EthereumTxEnvelope, - Block = crate::node::primitives::BscBlock, - >, + BlockHeader = alloy_consensus::Header, + SignedTx = alloy_consensus::EthereumTxEnvelope, + Block = crate::node::primitives::BscBlock, + >, { fn new( bid: Bid, @@ -807,7 +816,8 @@ where let base_fee: u64 = builder.evm().block().basefee(); let blob_params = self.chain_spec.blob_params_at_timestamp(self.attributes.timestamp()); let header = self.mining_ctx.header.as_ref().unwrap(); - let blob_eligible = is_blob_eligible_block(&self.chain_spec, header.number, header.timestamp); + let blob_eligible = + is_blob_eligible_block(&self.chain_spec, header.number, header.timestamp); let mut max_blob_count = blob_params.as_ref().map(|params| params.max_blob_count).unwrap_or_default(); if !blob_eligible { @@ -848,7 +858,13 @@ where // we can't fit this transaction into the block, so we need to mark it as invalid // which also removes all dependent transaction from the iterator before we can // continue - trace!("bidSimulator: gas limit exceeded, ignore tx:{}, tx gas limit:{}, block gas limit:{}, runtime gasused:{}", tx_hash, recovered_tx.gas_limit(), block_gas_limit, self.gas_used); + trace!( + "bidSimulator: gas limit exceeded, ignore tx:{}, tx gas limit:{}, block gas limit:{}, runtime gasused:{}", + tx_hash, + recovered_tx.gas_limit(), + block_gas_limit, + self.gas_used + ); continue; } } @@ -859,7 +875,10 @@ where if self.block_blob_count + tx_blob_count > max_blob_count { if from_pool { - trace!("bidSimulator: blob transaction limit exceeded, ignore tx:{}, tx blob count:{}, block blob count:{}, max blob count:{}", tx_hash, tx_blob_count, self.block_blob_count, max_blob_count); + trace!( + "bidSimulator: blob transaction limit exceeded, ignore tx:{}, tx blob count:{}, block blob count:{}, max blob count:{}", + tx_hash, tx_blob_count, self.block_blob_count, max_blob_count + ); continue; } debug!(target: "payload_builder", tx=?tx_hash, ?self.block_blob_count, "skipping blob transaction because it would exceed the max blob count per block"); @@ -884,14 +903,20 @@ where debug!(target: "payload_builder", %error, ?recovered_tx, "skipping invalid transaction and its descendants"); } if from_pool { - trace!("bidSimulator: invalid transaction, ignore tx:{}, error:{}, recovered tx:{:?}", tx_hash, error, recovered_tx); + trace!( + "bidSimulator: invalid transaction, ignore tx:{}, error:{}, recovered tx:{:?}", + tx_hash, error, recovered_tx + ); continue; } return Err("invalid transaction".into()); } Err(err) => { if from_pool { - trace!("bidSimulator: invalid transaction, ignore tx:{}, error:{}, recovered tx:{:?}", tx_hash, err, recovered_tx); + trace!( + "bidSimulator: invalid transaction, ignore tx:{}, error:{}, recovered tx:{:?}", + tx_hash, err, recovered_tx + ); continue; } return Err(Box::new(PayloadBuilderError::evm(err))); @@ -909,7 +934,10 @@ where ) { debug!("Failed to insert blob sidecar for tx {:?}: {:?}", tx_hash, e); if from_pool { - trace!("bidSimulator: failed to insert blob sidecar, ignore tx:{}, error:{}, recovered tx:{:?}", tx_hash, e, recovered_tx); + trace!( + "bidSimulator: failed to insert blob sidecar, ignore tx:{}, error:{}, recovered tx:{:?}", + tx_hash, e, recovered_tx + ); continue; } return Err("Failed to insert blob sidecar".into()); diff --git a/src/node/miner/bsc_miner.rs b/src/node/miner/bsc_miner.rs index 5f6a65df..6cffc266 100644 --- a/src/node/miner/bsc_miner.rs +++ b/src/node/miner/bsc_miner.rs @@ -1045,7 +1045,7 @@ where if self.submit_built_payload { if let Some(sender) = get_block_import_mined_sender() { - let incoming: IncomingMinedBlock = (payload, msg.clone()); + let incoming: IncomingMinedBlock = (payload, msg); if sender.send(incoming).is_err() { warn!("Failed to send mined block to import service due to channel closed"); return Err( @@ -1062,7 +1062,7 @@ where } } else if let Some(sender) = get_block_import_sender() { let peer_id = get_local_peer_id_or_default(); - let incoming: IncomingBlock = (msg.clone(), peer_id); + let incoming: IncomingBlock = (msg, peer_id); if sender.send(incoming).is_err() { warn!("Failed to send built block to import service due to channel closed"); return Err( diff --git a/src/node/miner/mod.rs b/src/node/miner/mod.rs index 467b4b6c..7bfd8fa4 100644 --- a/src/node/miner/mod.rs +++ b/src/node/miner/mod.rs @@ -1,9 +1,9 @@ -pub mod payload; -pub mod util; -pub mod signer; +pub mod bid_simulator; pub mod bsc_miner; pub mod config; -pub mod bid_simulator; +pub mod payload; +pub mod signer; +pub mod util; pub use bsc_miner::BscMiner; -pub use config::{MiningConfig, keystore}; \ No newline at end of file +pub use config::{keystore, MiningConfig}; diff --git a/src/node/miner/payload.rs b/src/node/miner/payload.rs index 75843d8c..3eafc232 100644 --- a/src/node/miner/payload.rs +++ b/src/node/miner/payload.rs @@ -18,10 +18,11 @@ use alloy_consensus::{BlockHeader, Transaction}; use alloy_evm::block::BlockExecutor; use alloy_evm::Evm; use alloy_primitives::U256; +use either::Either; use reth::payload::EthPayloadBuilderAttributes; +use reth::transaction_pool::BestTransactionsAttributes; use reth::transaction_pool::error::Eip4844PoolTransactionError; use reth::transaction_pool::error::InvalidPoolTransactionError; -use reth::transaction_pool::BestTransactionsAttributes; use reth::transaction_pool::{PoolTransaction, TransactionPool}; use reth_basic_payload_builder::PayloadConfig; use reth_chainspec::EthChainSpec; @@ -33,7 +34,6 @@ use reth_evm::{ConfigureEvm, NextBlockEnvAttributes}; use reth_execution_types::BlockExecutionOutput; use reth_payload_primitives::PayloadBuilderAttributes; use reth_payload_primitives::{BuiltPayload, BuiltPayloadExecutedBlock, PayloadBuilderError}; -use either::Either; use once_cell::sync::Lazy; use revm_context_interface::Block as EvmBlock; use reth_primitives::{HeaderTy, SealedHeader}; @@ -313,11 +313,11 @@ where Client: StateProviderFactory + 'static, EvmConfig: ConfigureEvm + 'static, ::Primitives: reth_primitives_traits::NodePrimitives< - BlockHeader = alloy_consensus::Header, - SignedTx = alloy_consensus::EthereumTxEnvelope, - Block = crate::node::primitives::BscBlock, - Receipt = reth_ethereum_primitives::Receipt, - >, + BlockHeader = alloy_consensus::Header, + SignedTx = alloy_consensus::EthereumTxEnvelope, + Block = crate::node::primitives::BscBlock, + Receipt = reth_ethereum_primitives::Receipt, + >, Pool: TransactionPool> + 'static, { pub const fn new( @@ -540,7 +540,9 @@ where continue; } let tx_start = std::time::Instant::now(); - let mut blob_tx_sidecar: Option> = None; + let mut blob_tx_sidecar: Option< + Arc, + > = None; trace!( target: "payload_builder", trace_id, @@ -815,7 +817,8 @@ where sealed_block = Arc::new(plain.into()); let requests = execution_result.requests.clone(); - let execution_outcome = BlockExecutionOutput { state: db.take_bundle(), result: execution_result }; + let execution_outcome = + BlockExecutionOutput { state: db.take_bundle(), result: execution_result }; let executed: BuiltPayloadExecutedBlock<_> = BuiltPayloadExecutedBlock { recovered_block: Arc::new(block), execution_output: Arc::new(execution_outcome), @@ -971,7 +974,8 @@ where ); let requests = execution_result.requests.clone(); - let execution_outcome = BlockExecutionOutput { state: db.take_bundle(), result: execution_result }; + let execution_outcome = + BlockExecutionOutput { state: db.take_bundle(), result: execution_result }; let executed: BuiltPayloadExecutedBlock<_> = BuiltPayloadExecutedBlock { recovered_block: Arc::new(block), execution_output: Arc::new(execution_outcome), @@ -1113,11 +1117,11 @@ where + 'static, EvmConfig: ConfigureEvm + 'static, ::Primitives: reth_primitives_traits::NodePrimitives< - BlockHeader = alloy_consensus::Header, - SignedTx = alloy_consensus::EthereumTxEnvelope, - Block = crate::node::primitives::BscBlock, - Receipt = reth_ethereum_primitives::Receipt, - >, + BlockHeader = alloy_consensus::Header, + SignedTx = alloy_consensus::EthereumTxEnvelope, + Block = crate::node::primitives::BscBlock, + Receipt = reth_ethereum_primitives::Receipt, + >, Pool: TransactionPool> + 'static, { /// Creates a new BscPayloadJob and returns both the job and its handle diff --git a/src/node/miner/signer.rs b/src/node/miner/signer.rs index ed326932..fa2b8518 100644 --- a/src/node/miner/signer.rs +++ b/src/node/miner/signer.rs @@ -1,13 +1,13 @@ use once_cell::sync::OnceCell; -use std::sync::Arc; use reth_primitives::{Transaction, TransactionSigned}; +use std::sync::Arc; // reth signing helper avoided to not materialize a B256 from secret -use alloy_primitives::B256; -use alloy_consensus::{SignableTransaction, Header}; use crate::consensus::parlia::{hash_with_chain_id, EXTRA_SEAL_LEN}; -use secp256k1::{SECP256K1, Message, SecretKey}; -use zeroize::Zeroizing; +use alloy_consensus::{Header, SignableTransaction}; +use alloy_primitives::B256; use k256::ecdsa::SigningKey as K256SigningKey; +use secp256k1::{Message, SecretKey, SECP256K1}; +use zeroize::Zeroizing; pub struct MinerSigner { // Wrap raw key bytes to ensure zeroize-on-drop; reconstruct SecretKey as needed @@ -40,7 +40,10 @@ impl MinerSigner { Self { secret_bytes: Zeroizing::new(secret_key.secret_bytes()) } } - pub fn sign_transaction(&self, transaction: Transaction) -> Result { + pub fn sign_transaction( + &self, + transaction: Transaction, + ) -> Result { // Sign directly with libsecp256k1 using the in-memory secret to avoid constructing B256 of the key. let msg_hash = transaction.signature_hash(); let message = Message::from_digest(msg_hash.0); @@ -59,20 +62,24 @@ impl MinerSigner { Ok(signed) } - pub fn seal_header(&self, header: &Header, chain_id: u64) -> Result<[u8; EXTRA_SEAL_LEN], SignerError> { + pub fn seal_header( + &self, + header: &Header, + chain_id: u64, + ) -> Result<[u8; EXTRA_SEAL_LEN], SignerError> { let hash_data = hash_with_chain_id(header, chain_id); let message = Message::from_digest(hash_data.0); let sk = SecretKey::from_slice(self.secret_bytes.as_slice()) .map_err(|e| SignerError::SigningFailed(format!("Invalid private key: {}", e)))?; let recoverable_sig = SECP256K1.sign_ecdsa_recoverable(&message, &sk); let (recovery_id, signature_bytes) = recoverable_sig.serialize_compact(); - + // [r(32) + s(32) + recovery_id(1)] let mut sig_bytes = [0u8; EXTRA_SEAL_LEN]; sig_bytes[0..64].copy_from_slice(&signature_bytes); let raw_recovery_id = i32::from(recovery_id) as u8; sig_bytes[64] = raw_recovery_id; - + Ok(sig_bytes) } } @@ -82,9 +89,7 @@ pub fn init_global_signer(private_key: B256) -> Result<(), SignerError> { let sk = SecretKey::from_slice(private_key.as_ref()) .map_err(|e| SignerError::SigningFailed(format!("Invalid private key: {}", e)))?; let signer = Arc::new(MinerSigner::new(sk)); - GLOBAL_SIGNER - .set(signer) - .map_err(|_| SignerError::AlreadyInitialized) + GLOBAL_SIGNER.set(signer).map_err(|_| SignerError::AlreadyInitialized) } /// Preferred initializer: use a k256 SigningKey to avoid exposing raw bytes. @@ -94,9 +99,7 @@ pub fn init_global_signer_from_k256(signing_key: &K256SigningKey) -> Result<(), let sk = SecretKey::from_slice(&raw) .map_err(|e| SignerError::SigningFailed(format!("Invalid private key: {}", e)))?; let signer = Arc::new(MinerSigner::new(sk)); - GLOBAL_SIGNER - .set(signer) - .map_err(|_| SignerError::AlreadyInitialized) + GLOBAL_SIGNER.set(signer).map_err(|_| SignerError::AlreadyInitialized) } pub fn get_global_signer() -> Option<&'static Arc> { @@ -104,9 +107,8 @@ pub fn get_global_signer() -> Option<&'static Arc> { } pub fn sign_system_transaction(tx: Transaction) -> Result { - let signer = GLOBAL_SIGNER.get() - .ok_or(SignerError::NotInitialized)?; - + let signer = GLOBAL_SIGNER.get().ok_or(SignerError::NotInitialized)?; + signer.sign_transaction(tx) } @@ -114,9 +116,11 @@ pub fn is_signer_initialized() -> bool { GLOBAL_SIGNER.get().is_some() } -pub fn seal_header_with_global_signer(header: &Header, chain_id: u64) -> Result<[u8; EXTRA_SEAL_LEN], SignerError> { - let signer = GLOBAL_SIGNER.get() - .ok_or(SignerError::NotInitialized)?; +pub fn seal_header_with_global_signer( + header: &Header, + chain_id: u64, +) -> Result<[u8; EXTRA_SEAL_LEN], SignerError> { + let signer = GLOBAL_SIGNER.get().ok_or(SignerError::NotInitialized)?; signer.seal_header(header, chain_id) } @@ -126,8 +130,8 @@ mod tests { use crate::consensus::parlia::{hash_with_chain_id, EXTRA_SEAL_LEN}; use crate::node::miner::config::keystore::get_validator_address; use alloy_consensus::Header; - use alloy_primitives::{keccak256, Address, Bytes, TxKind, U256}; use alloy_consensus::TxLegacy; + use alloy_primitives::{keccak256, Address, Bytes, TxKind, U256}; use reth_primitives::Transaction; use reth_primitives_traits::SignerRecoverable; use secp256k1::{ecdsa::RecoverableSignature, ecdsa::RecoveryId}; diff --git a/src/node/network/block_import/handle.rs b/src/node/network/block_import/handle.rs index 2a699a41..adfde6b3 100644 --- a/src/node/network/block_import/handle.rs +++ b/src/node/network/block_import/handle.rs @@ -1,13 +1,13 @@ use std::task::{Context, Poll}; use reth_engine_primitives::EngineTypes; +use reth_eth_wire_types::broadcast::NewBlockHashes; use reth_network::import::BlockImportError; use reth_network_api::PeerId; use reth_payload_primitives::PayloadTypes; use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; -use reth_eth_wire_types::broadcast::NewBlockHashes; -use super::service::{BlockMsg, ImportEvent, IncomingBlock, Outcome, IncomingHashes}; +use super::service::{BlockMsg, ImportEvent, IncomingBlock, IncomingHashes, Outcome}; /// A handle for interacting with the block import service. /// @@ -46,7 +46,11 @@ impl ImportHandle { /// Sends block hashes to the service for downloading. /// Returns a [`BlockImportError`] if the channel to the import service is closed. - pub fn send_hashes(&self, hashes: NewBlockHashes, peer_id: PeerId) -> Result<(), BlockImportError> { + pub fn send_hashes( + &self, + hashes: NewBlockHashes, + peer_id: PeerId, + ) -> Result<(), BlockImportError> { self.to_hashes .send((hashes, peer_id)) .map_err(|_| BlockImportError::Other("block hash service channel closed".into())) diff --git a/src/node/network/block_import/service.rs b/src/node/network/block_import/service.rs index 8c95988e..aba12e3b 100644 --- a/src/node/network/block_import/service.rs +++ b/src/node/network/block_import/service.rs @@ -510,26 +510,29 @@ where /// Transfer the block to EVN peers if from proxied validators or validator address. fn transfer_to_evn_peers(&self, block: BlockMsg) -> Result<(), Box> { - let mining_config = crate::node::miner::config::get_global_mining_config().ok_or("Mining config is not set")?; - let cfg = crate::node::network::evn::get_global_evn_config().ok_or("EVN config is not set")?; + let mining_config = crate::node::miner::config::get_global_mining_config() + .ok_or("Mining config is not set")?; + let cfg = + crate::node::network::evn::get_global_evn_config().ok_or("EVN config is not set")?; if !cfg.enabled { return Ok(()); } let header_ref = &block.block.0.block.header; let coinbase = header_ref.beneficiary; // If from proxied validators or validator address, target EVN peers with ETH NewBlockHashes. - if cfg.proxyed_validators.contains(&coinbase) || (mining_config.enabled && mining_config.validator_address.unwrap_or_default() == coinbase) { + if cfg.proxyed_validators.contains(&coinbase) + || (mining_config.enabled + && mining_config.validator_address.unwrap_or_default() == coinbase) + { if let Some(net) = crate::shared::get_network_handle() { let peers = crate::node::network::evn_peers::snapshot(); for (peer_id, info) in peers { // Send to EVN peers or proxyed peers - let is_proxyed = crate::node::network::bsc_protocol::registry::is_proxyed_peer(&peer_id); + let is_proxyed = + crate::node::network::bsc_protocol::registry::is_proxyed_peer(&peer_id); if info.is_evn || is_proxyed { // Send full NewBlock to EVN/proxyed peers to avoid re-fetching. - net.send_eth_message( - peer_id, - PeerMessage::NewBlock(block.clone()), - ); + net.send_eth_message(peer_id, PeerMessage::NewBlock(block.clone())); tracing::debug!(target: "bsc::block_import", "Sent full NewBlock to EVN/proxyed peer: number = {:?}, hash = {:?}, peer = {:?}", block.block.0.block.header.number, block.hash, peer_id); } } diff --git a/src/node/network/bootnodes.rs b/src/node/network/bootnodes.rs index 789c287a..02b0df86 100644 --- a/src/node/network/bootnodes.rs +++ b/src/node/network/bootnodes.rs @@ -37,10 +37,9 @@ pub static BSC_TESTNET_BOOTNODES: &[&str] = &[ "enode://665cf77ca26a8421cfe61a52ac312958308d4912e78ce8e0f61d6902e4494d4cc38f9b0dd1b23a427a7a5734e27e5d9729231426b06bb9c73b56a142f83f6b68@52.72.123.113:30311", ]; - /// Bsc qanet boot nodes. pub static BSC_QANET_BOOTNODES: &[&str] = &[ "enode://b78cba3067e3043e0d6b72931c29ae463c10533b149bdc23de54304cacf5f434e903ae2b8d4485f1ad103e6882301a77f03b679a51e169ab4afcab635cb614c2@10.179.43.231:30311", "enode://c1362b6d4a9693d9372c0c82f3186bfb9383a6ffe3e147507e5515474e61bf192cbf0599a7a00b878cc154582b96174cc6d53cccdcd88d110f721d6b30443388@10.179.41.29:30311", "enode://4c983187454c632312d35ccbbb5b801ec0081c202eb2fa4a506e218492f46312285c66aa7b470b43a1d0f90e1a1c7247e3ad2c6971ae8bcda9ad063f9c54af6b@10.179.41.103:30311" -]; \ No newline at end of file +]; diff --git a/src/node/network/bsc_protocol/protocol/handler.rs b/src/node/network/bsc_protocol/protocol/handler.rs index 9788f570..5823fd2e 100644 --- a/src/node/network/bsc_protocol/protocol/handler.rs +++ b/src/node/network/bsc_protocol/protocol/handler.rs @@ -1,12 +1,14 @@ -use reth_network_api::{PeerId, Direction}; +use reth_eth_wire::{ + capability::SharedCapabilities, multiplex::ProtocolConnection, protocol::Protocol, +}; use reth_network::protocol::{ConnectionHandler, OnNotSupported, ProtocolHandler}; -use reth_eth_wire::{capability::SharedCapabilities, multiplex::ProtocolConnection, protocol::Protocol}; +use reth_network_api::{Direction, PeerId}; use std::net::SocketAddr; use tokio::sync::mpsc; use super::proto::BscProtoMessage; -use crate::node::network::bsc_protocol::stream::{BscProtocolConnection}; use crate::node::network::bsc_protocol::registry; +use crate::node::network::bsc_protocol::stream::BscProtocolConnection; use reth_network::Peers; #[derive(Clone, Debug, Default)] @@ -18,15 +20,25 @@ pub struct BscConnectionHandlerV2; impl ProtocolHandler for BscProtocolHandlerV2 { type ConnectionHandler = BscConnectionHandlerV2; - fn on_incoming(&self, _socket_addr: SocketAddr) -> Option { Some(BscConnectionHandlerV2) } + fn on_incoming(&self, _socket_addr: SocketAddr) -> Option { + Some(BscConnectionHandlerV2) + } - fn on_outgoing(&self, _socket_addr: SocketAddr, _peer_id: PeerId) -> Option { Some(BscConnectionHandlerV2) } + fn on_outgoing( + &self, + _socket_addr: SocketAddr, + _peer_id: PeerId, + ) -> Option { + Some(BscConnectionHandlerV2) + } } impl ConnectionHandler for BscConnectionHandlerV2 { type Connection = BscProtocolConnection; - fn protocol(&self) -> Protocol { BscProtoMessage::protocol_for(2) } + fn protocol(&self) -> Protocol { + BscProtoMessage::protocol_for(2) + } fn on_unsupported_by_peer( self, @@ -78,7 +90,11 @@ impl ProtocolHandler for BscProtocolHandlerV1 { Some(BscConnectionHandlerV1) } - fn on_outgoing(&self, _socket_addr: SocketAddr, _peer_id: PeerId) -> Option { + fn on_outgoing( + &self, + _socket_addr: SocketAddr, + _peer_id: PeerId, + ) -> Option { Some(BscConnectionHandlerV1) } } @@ -86,7 +102,9 @@ impl ProtocolHandler for BscProtocolHandlerV1 { impl ConnectionHandler for BscConnectionHandlerV1 { type Connection = BscProtocolConnection; - fn protocol(&self) -> Protocol { BscProtoMessage::protocol_for(1) } + fn protocol(&self) -> Protocol { + BscProtoMessage::protocol_for(1) + } fn on_unsupported_by_peer( self, diff --git a/src/node/network/bsc_protocol/protocol/proto.rs b/src/node/network/bsc_protocol/protocol/proto.rs index 596a59d9..87ed9453 100644 --- a/src/node/network/bsc_protocol/protocol/proto.rs +++ b/src/node/network/bsc_protocol/protocol/proto.rs @@ -23,7 +23,9 @@ pub struct BscProtoMessage; impl BscProtoMessage { /// Returns the capability for the `bsc` protocol version. - pub fn capability_for(version: u64) -> Capability { Capability::new_static(BSC_PROTOCOL_NAME, version as usize) } + pub fn capability_for(version: u64) -> Capability { + Capability::new_static(BSC_PROTOCOL_NAME, version as usize) + } /// Returns the protocol for the `bsc` protocol with the message count for the given version. pub fn protocol_for(version: u64) -> Protocol { @@ -38,15 +40,15 @@ impl BscProtoMessage { #[cfg(test)] mod tests { - use alloy_primitives::{hex, B256, FixedBytes}; - use alloy_rlp::{RlpEncodable, RlpDecodable}; use crate::consensus::parlia::vote::{VoteData, VoteEnvelope}; + use alloy_primitives::{hex, FixedBytes, B256}; + use alloy_rlp::{RlpDecodable, RlpEncodable}; /// Wrapper struct to match Go's RLP encoding of struct{Votes []*VoteEnvelope} #[derive(RlpEncodable, RlpDecodable)] struct VotesWrapper(Vec); - fn b256(s: &str) -> B256 { + fn b256(s: &str) -> B256 { let hex_str = s.trim_start_matches("0x"); B256::from_slice(&hex::decode(hex_str).unwrap()) } @@ -79,23 +81,83 @@ mod tests { ]; let vote_data_set = [ - (0u64, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 1u64, "0xd0bc67b50915467ada963c35ee00950f664788e47da8139d8c178653171034f1"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 2, "0xc2d18d5a59d65da573f70c4d30448482418894e018b0d189db24ea4fd02d7aa1"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 4, "0xbd1bdaf8a8f5c00c464df2856a9e2ef23b8dcc906e6490d3cd295ebb5eb124c3"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 8, "0x3073782ecabb5ef0673e95962273482347a2c7b30a0a7124c664443d0a43f1e1"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 16, "0xc119833266327fd7e0cd929c6a847ae7d1689df5066dfdde2e52f51c0ecbcc3f"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 32, "0x3b5650bcb98381e463871a15a3f601cdc26843d76f4d3461333d7feae38a1786"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 64, "0x5e38b4d98904178d60d58f5bc1687b0c7df114a51f2007d3ee3e6e732539f130"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 128, "0xa4a64a7d511d3ff6982b5a79e9a485508477b98996c570a220f9daea0c7682f8"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 256, "0xd313672c2653fc13e75a9dafdcee93f444caf2cffb04585d3e306fd15418b7e2"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 512, "0x3c5fe2e5439ca7a7f1a3de7d5c0914c37261451c87654397dd45f207109839ae"), - (0, "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", 1024, "0x088eeeb07acff0db3ae2585195e9fd23bdf54b55077cab87d1632b08dd2c043b"), + ( + 0u64, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 1u64, + "0xd0bc67b50915467ada963c35ee00950f664788e47da8139d8c178653171034f1", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 2, + "0xc2d18d5a59d65da573f70c4d30448482418894e018b0d189db24ea4fd02d7aa1", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 4, + "0xbd1bdaf8a8f5c00c464df2856a9e2ef23b8dcc906e6490d3cd295ebb5eb124c3", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 8, + "0x3073782ecabb5ef0673e95962273482347a2c7b30a0a7124c664443d0a43f1e1", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 16, + "0xc119833266327fd7e0cd929c6a847ae7d1689df5066dfdde2e52f51c0ecbcc3f", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 32, + "0x3b5650bcb98381e463871a15a3f601cdc26843d76f4d3461333d7feae38a1786", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 64, + "0x5e38b4d98904178d60d58f5bc1687b0c7df114a51f2007d3ee3e6e732539f130", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 128, + "0xa4a64a7d511d3ff6982b5a79e9a485508477b98996c570a220f9daea0c7682f8", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 256, + "0xd313672c2653fc13e75a9dafdcee93f444caf2cffb04585d3e306fd15418b7e2", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 512, + "0x3c5fe2e5439ca7a7f1a3de7d5c0914c37261451c87654397dd45f207109839ae", + ), + ( + 0, + "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34", + 1024, + "0x088eeeb07acff0db3ae2585195e9fd23bdf54b55077cab87d1632b08dd2c043b", + ), ]; let vote_address = bytes48(bls_pub); let mut votes: Vec = Vec::with_capacity(vote_data_set.len()); for (i, (sn, sh, tn, th)) in vote_data_set.into_iter().enumerate() { - let data = VoteData { source_number: sn, source_hash: b256(sh), target_number: tn, target_hash: b256(th) }; + let data = VoteData { + source_number: sn, + source_hash: b256(sh), + target_number: tn, + target_hash: b256(th), + }; let signature = bytes96(signatures[i]); votes.push(VoteEnvelope { vote_address, signature, data }); } diff --git a/src/node/network/evn.rs b/src/node/network/evn.rs index b1d35233..1bc66aff 100644 --- a/src/node/network/evn.rs +++ b/src/node/network/evn.rs @@ -1,5 +1,8 @@ use alloy_primitives::Address; -use std::sync::{OnceLock, atomic::{AtomicBool, Ordering}}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + OnceLock, +}; use tokio::sync::broadcast; /// EVN configuration @@ -17,7 +20,9 @@ pub struct EvnConfig { static GLOBAL_EVN_CONFIG: OnceLock = OnceLock::new(); /// Sets the global EVN config. Returns an error if already set. -pub fn set_global_evn_config(cfg: EvnConfig) -> Result<(), EvnConfig> { GLOBAL_EVN_CONFIG.set(cfg) } +pub fn set_global_evn_config(cfg: EvnConfig) -> Result<(), EvnConfig> { + GLOBAL_EVN_CONFIG.set(cfg) +} /// Convenience: set only enabled flag. pub fn set_global_evn_enabled(enabled: bool) -> Result<(), bool> { @@ -30,7 +35,9 @@ pub fn set_global_evn_enabled(enabled: bool) -> Result<(), bool> { } /// Returns the global EVN config if set. -pub fn get_global_evn_config() -> Option<&'static EvnConfig> { GLOBAL_EVN_CONFIG.get() } +pub fn get_global_evn_config() -> Option<&'static EvnConfig> { + GLOBAL_EVN_CONFIG.get() +} /// Returns true if EVN is enabled globally either via explicit global set or /// via environment variable fallback. @@ -62,10 +69,14 @@ pub fn set_evn_synced(synced: bool) { } /// Returns whether EVN is considered synced/armed. -pub fn is_evn_synced() -> bool { EVN_SYNCED.load(Ordering::Relaxed) } +pub fn is_evn_synced() -> bool { + EVN_SYNCED.load(Ordering::Relaxed) +} /// EVN is ready only when enabled and synced (post-initial-sync) -pub fn is_evn_ready() -> bool { is_evn_enabled() && is_evn_synced() } +pub fn is_evn_ready() -> bool { + is_evn_enabled() && is_evn_synced() +} /// Returns a receiver for EVN armed notifications; creates the channel if missing. pub fn subscribe_evn_armed() -> broadcast::Receiver<()> { diff --git a/src/node/network/evn_peers.rs b/src/node/network/evn_peers.rs index c9844138..7d0a2c40 100644 --- a/src/node/network/evn_peers.rs +++ b/src/node/network/evn_peers.rs @@ -21,8 +21,7 @@ static EVN_PEERS: Lazy>> = Lazy::new(|| RwLock::new(HashMap::new())); /// Global on-chain NodeIDs set (normalized hex strings without 0x) -static ONCHAIN_NODEIDS: Lazy>> = - Lazy::new(|| RwLock::new(HashSet::new())); +static ONCHAIN_NODEIDS: Lazy>> = Lazy::new(|| RwLock::new(HashSet::new())); pub fn peer_id_to_node_id(peer: PeerId) -> String { alloy_primitives::hex::encode(keccak256(peer.as_slice())) @@ -31,16 +30,27 @@ pub fn peer_id_to_node_id(peer: PeerId) -> String { /// Attempt to mark a peer as EVN by whitelist entries in the global EVN config. pub fn mark_evn_if_whitelisted(peer: PeerId) { if let Some(cfg) = crate::node::network::evn::get_global_evn_config() { - if !cfg.enabled { return; } - if cfg.whitelist_nodeids.is_empty() { return; } + if !cfg.enabled { + return; + } + if cfg.whitelist_nodeids.is_empty() { + return; + } // Compare peer's ID string with whitelist entries let node_id = peer_id_to_node_id(peer); let is_whitelisted = cfg.whitelist_nodeids.contains(&node_id); if is_whitelisted { if let Ok(mut map) = EVN_PEERS.write() { - map.entry(peer).and_modify(|e| { e.is_evn = true; e.reason = Some(EvnMarkReason::Whitelist); }) - .or_insert(EvnPeerInfo { is_evn: true, reason: Some(EvnMarkReason::Whitelist) }); + map.entry(peer) + .and_modify(|e| { + e.is_evn = true; + e.reason = Some(EvnMarkReason::Whitelist); + }) + .or_insert(EvnPeerInfo { + is_evn: true, + reason: Some(EvnMarkReason::Whitelist), + }); } } } @@ -49,19 +59,31 @@ pub fn mark_evn_if_whitelisted(peer: PeerId) { /// Mark a peer as EVN due to onchain validator mapping. pub fn mark_evn_onchain(peer: PeerId) { if let Ok(mut map) = EVN_PEERS.write() { - map.entry(peer).and_modify(|e| { e.is_evn = true; e.reason = Some(EvnMarkReason::OnchainValidator); }) + map.entry(peer) + .and_modify(|e| { + e.is_evn = true; + e.reason = Some(EvnMarkReason::OnchainValidator); + }) .or_insert(EvnPeerInfo { is_evn: true, reason: Some(EvnMarkReason::OnchainValidator) }); } } /// Query whether a peer is currently marked EVN. pub fn is_evn_peer(peer: PeerId) -> bool { - if let Ok(map) = EVN_PEERS.read() { map.get(&peer).map(|i| i.is_evn).unwrap_or(false) } else { false } + if let Ok(map) = EVN_PEERS.read() { + map.get(&peer).map(|i| i.is_evn).unwrap_or(false) + } else { + false + } } /// Current EVN peer snapshot pub fn snapshot() -> Vec<(PeerId, EvnPeerInfo)> { - if let Ok(map) = EVN_PEERS.read() { map.iter().map(|(k,v)| (*k, v.clone())).collect() } else { Vec::new() } + if let Ok(map) = EVN_PEERS.read() { + map.iter().map(|(k, v)| (*k, v.clone())).collect() + } else { + Vec::new() + } } /// Update the on-chain NodeIDs cache with the provided list @@ -76,5 +98,9 @@ pub fn update_onchain_nodeids(ids: Vec<[u8; 32]>) { /// Get a snapshot of on-chain NodeIDs as normalized hex strings pub fn get_onchain_nodeids_set() -> HashSet { - if let Ok(set) = ONCHAIN_NODEIDS.read() { set.clone() } else { HashSet::new() } + if let Ok(set) = ONCHAIN_NODEIDS.read() { + set.clone() + } else { + HashSet::new() + } } diff --git a/src/node/network/handshake.rs b/src/node/network/handshake.rs index f233da20..cd38a391 100644 --- a/src/node/network/handshake.rs +++ b/src/node/network/handshake.rs @@ -30,9 +30,13 @@ impl BscHandshake { // This mirrors the BSC EVN behavior where validator/sentry nodes // avoid mempool flooding between EVN peers. let evn_enabled = crate::node::network::evn::is_evn_ready(); - let disable_tx_broadcast_forbidden = crate::node::network::evn::get_global_evn_config().map(|cfg| cfg.disable_tx_broadcast_forbidden).unwrap_or(false); + let disable_tx_broadcast_forbidden = crate::node::network::evn::get_global_evn_config() + .map(|cfg| cfg.disable_tx_broadcast_forbidden) + .unwrap_or(false); let upgrade_msg = UpgradeStatus { - extension: UpgradeStatusExtension { disable_peer_tx_broadcast: evn_enabled && !disable_tx_broadcast_forbidden }, + extension: UpgradeStatusExtension { + disable_peer_tx_broadcast: evn_enabled && !disable_tx_broadcast_forbidden, + }, }; tracing::debug!(target: "bsc_handshake", "Sending upgrade status message, EVN enabled: {}, disable tx broadcast forbidden: {}", evn_enabled, disable_tx_broadcast_forbidden); unauth.start_send_unpin(upgrade_msg.into_rlpx())?; diff --git a/src/node/network/mod.rs b/src/node/network/mod.rs index 46e9d4e4..530fd84c 100644 --- a/src/node/network/mod.rs +++ b/src/node/network/mod.rs @@ -1,20 +1,28 @@ #![allow(clippy::owned_cow)] +use crate::node::miner::signer::{is_signer_initialized, sign_system_transaction}; use crate::{ - BscBlock, chainspec::BscChainSpec, node::{ - BscNode, engine_api::payload::BscPayloadTypes, network::{ - block_import::{BscBlockImport, handle::ImportHandle}, + chainspec::BscChainSpec, + node::{ + engine_api::payload::BscPayloadTypes, + network::{ + block_import::{handle::ImportHandle, BscBlockImport}, evn_peers::{get_onchain_nodeids_set, peer_id_to_node_id}, - }, primitives::{BscBlobTransactionSidecar, BscPrimitives} - } + }, + primitives::{BscBlobTransactionSidecar, BscPrimitives}, + BscNode, + }, + BscBlock, }; use alloy_primitives::{Address, U256}; use alloy_rlp::{Decodable, Encodable}; +use alloy_rpc_types::TransactionRequest as RpcTransactionRequest; use handshake::BscHandshake; use reth::{ api::{FullNodeTypes, TxTy}, builder::{components::NetworkBuilder, BuilderContext}, transaction_pool::{PoolTransaction, TransactionPool}, }; +use reth_chainspec::EthChainSpec; use reth_discv4::Discv4Config; use reth_engine_primitives::ConsensusEngineHandle; use reth_eth_wire::{BasicNetworkPrimitives, NewBlock, NewBlockPayload}; @@ -27,11 +35,6 @@ use reth_primitives::TransactionSigned; use std::{sync::Arc, time::Duration}; use tokio::sync::{mpsc, oneshot, Mutex}; use tracing::{debug, info, warn}; -use alloy_rpc_types::{ - TransactionRequest as RpcTransactionRequest, -}; -use crate::node::miner::signer::{is_signer_initialized, sign_system_transaction}; -use reth_chainspec::EthChainSpec; pub mod block_import; pub(crate) mod blocks_by_range; @@ -510,16 +513,27 @@ async fn register_nodeids_actions( to_add: Vec<[u8; 32]>, to_remove: Vec<[u8; 32]>, ) -> Result<(), eyre::Error> { - let best_block_number = crate::shared::get_best_canonical_block_number().ok_or(eyre::eyre!("Best block number not found"))?; - let h = crate::shared::get_canonical_header_by_number(best_block_number).ok_or(eyre::eyre!("Header not found"))?; + let best_block_number = crate::shared::get_best_canonical_block_number() + .ok_or(eyre::eyre!("Best block number not found"))?; + let h = crate::shared::get_canonical_header_by_number(best_block_number) + .ok_or(eyre::eyre!("Header not found"))?; let state = provider.state_by_block_hash(h.hash_slow())?; - let acc = state.basic_account(&validator)?.ok_or(eyre::eyre!("Account not found for validator"))?; + let acc = + state.basic_account(&validator)?.ok_or(eyre::eyre!("Account not found for validator"))?; let mut next_nonce = acc.nonce; let chain_id = chain_spec.chain().id(); let onchain_nodeids_set = get_onchain_nodeids_set(); - let to_add: Vec<[u8; 32]>= to_add.iter().filter(|id| !onchain_nodeids_set.contains(&alloy_primitives::hex::encode(**id))).copied().collect(); - let to_remove: Vec<[u8; 32]>= to_remove.iter().filter(|id| onchain_nodeids_set.contains(&alloy_primitives::hex::encode(**id))).copied().collect(); + let to_add: Vec<[u8; 32]> = to_add + .iter() + .filter(|id| !onchain_nodeids_set.contains(&alloy_primitives::hex::encode(**id))) + .copied() + .collect(); + let to_remove: Vec<[u8; 32]> = to_remove + .iter() + .filter(|id| onchain_nodeids_set.contains(&alloy_primitives::hex::encode(**id))) + .copied() + .collect(); debug!(target: "bsc::evn", to_add = ?to_add, to_remove = ?to_remove, onchain_nodeids_set = ?onchain_nodeids_set, "refreshed to_add and to_remove"); let mut signed_batch: Vec = Vec::new(); if !to_add.is_empty() { diff --git a/src/node/network/upgrade_status.rs b/src/node/network/upgrade_status.rs index 2f9e5d19..8889a1b4 100644 --- a/src/node/network/upgrade_status.rs +++ b/src/node/network/upgrade_status.rs @@ -85,14 +85,29 @@ impl Decodable for UpgradeStatusExtension { mod tests { use super::*; use alloy_primitives::hex; - + #[test] fn test_decode_bsc_upgrade_status() { // Raw wire message captured from a BSC peer. let cases = vec![ - ("0bc180", UpgradeStatus { extension: UpgradeStatusExtension { disable_peer_tx_broadcast: false } }), - ("0bc2c180", UpgradeStatus { extension: UpgradeStatusExtension { disable_peer_tx_broadcast: false } }), - ("0bc2c101", UpgradeStatus { extension: UpgradeStatusExtension { disable_peer_tx_broadcast: true } }), + ( + "0bc180", + UpgradeStatus { + extension: UpgradeStatusExtension { disable_peer_tx_broadcast: false }, + }, + ), + ( + "0bc2c180", + UpgradeStatus { + extension: UpgradeStatusExtension { disable_peer_tx_broadcast: false }, + }, + ), + ( + "0bc2c101", + UpgradeStatus { + extension: UpgradeStatusExtension { disable_peer_tx_broadcast: true }, + }, + ), ]; for (raw, expected) in cases { let raw = hex::decode(raw).unwrap(); @@ -101,7 +116,10 @@ mod tests { println!("decoded: {:?}", decoded); assert_eq!(expected, decoded); let mut enc = BytesMut::new(); - UpgradeStatus { extension: UpgradeStatusExtension { disable_peer_tx_broadcast: false } }.encode(&mut enc); + UpgradeStatus { + extension: UpgradeStatusExtension { disable_peer_tx_broadcast: false }, + } + .encode(&mut enc); println!("enc: {:x?}", enc.freeze()); } } diff --git a/src/node/network/votes.rs b/src/node/network/votes.rs index 981c8495..93e0aaf0 100644 --- a/src/node/network/votes.rs +++ b/src/node/network/votes.rs @@ -15,17 +15,17 @@ impl Encodable for BscCapPacket { fn encode(&self, out: &mut dyn BufMut) { // Message ID should be sent as raw byte, not RLP-encoded out.put_u8(BscProtoMessageId::Capability as u8); - + // Encode as RLP list: [protocol_version, extra] // Extra is raw RLP data (like Go's rlp.RawValue), so insert directly let protocol_version_encoded = alloy_rlp::encode(self.protocol_version); - + // Calculate list payload length (protocol_version + raw extra data) let payload_length = protocol_version_encoded.len() + self.extra.len(); - - // Encode list header + + // Encode list header alloy_rlp::Header { list: true, payload_length }.encode(out); - + // Encode protocol version out.put_slice(&protocol_version_encoded); // Insert raw extra data directly (no additional RLP encoding) @@ -50,9 +50,9 @@ impl Decodable for BscCapPacket { if !header.list { return Err(alloy_rlp::Error::UnexpectedString); } - + let protocol_version = u64::decode(buf)?; - + // Extra is raw RLP data - read remaining bytes directly let remaining_len = header.payload_length - 1; // -1 for protocol_version (single byte) if buf.len() < remaining_len { @@ -111,10 +111,10 @@ pub fn handle_votes_broadcast(packet: VotesPacket) { if let Some(first) = packet.0.into_iter().next() { tracing::trace!(target: "bsc::vote", "insert first vote into local pool, target_number: {}, target_hash: {}", first.data.target_number, first.data.target_hash); votes::put_vote(first); - + // Update vote pool size metric - use once_cell::sync::Lazy; use crate::metrics::BscVoteMetrics; + use once_cell::sync::Lazy; static VOTE_METRICS: Lazy = Lazy::new(BscVoteMetrics::default); VOTE_METRICS.vote_pool_size.set(votes::len() as f64); } diff --git a/src/node/primitives.rs b/src/node/primitives.rs index be7d3bda..044ba45e 100644 --- a/src/node/primitives.rs +++ b/src/node/primitives.rs @@ -54,8 +54,9 @@ pub struct BscBlockBody { impl InMemorySize for BscBlockBody { fn size(&self) -> usize { - self.inner.size() + - self.sidecars + self.inner.size() + + self + .sidecars .as_ref() .map_or(0, |s| s.capacity() * core::mem::size_of::()) } diff --git a/src/node/vote_journal.rs b/src/node/vote_journal.rs index c91d528a..09a6ffc3 100644 --- a/src/node/vote_journal.rs +++ b/src/node/vote_journal.rs @@ -24,7 +24,9 @@ struct VoteDataLru { } impl VoteDataLru { - fn new(capacity: usize) -> Self { Self { capacity, order: VecDeque::new(), map: HashMap::new() } } + fn new(capacity: usize) -> Self { + Self { capacity, order: VecDeque::new(), map: HashMap::new() } + } fn add(&mut self, key: u64, value: VoteData) { if !self.map.contains_key(&key) { @@ -38,9 +40,13 @@ impl VoteDataLru { self.map.insert(key, value); } - fn contains(&self, key: u64) -> bool { self.map.contains_key(&key) } + fn contains(&self, key: u64) -> bool { + self.map.contains_key(&key) + } - fn get(&self, key: u64) -> Option { self.map.get(&key).cloned() } + fn get(&self, key: u64) -> Option { + self.map.get(&key).cloned() + } // no additional methods } @@ -54,13 +60,19 @@ pub struct VoteJournal { impl VoteJournal { fn resolve_default_path() -> PathBuf { // Priority: BSC_VOTE_JOURNAL_DIR -> RETH_DATADIR -> ./voteJournal - if let Ok(dir) = std::env::var("BSC_VOTE_JOURNAL_DIR") { return PathBuf::from(dir).join("votes.jsonl"); } - if let Ok(reth_dir) = std::env::var("RETH_DATADIR") { return PathBuf::from(reth_dir).join("voteJournal").join("votes.jsonl"); } + if let Ok(dir) = std::env::var("BSC_VOTE_JOURNAL_DIR") { + return PathBuf::from(dir).join("votes.jsonl"); + } + if let Ok(reth_dir) = std::env::var("RETH_DATADIR") { + return PathBuf::from(reth_dir).join("voteJournal").join("votes.jsonl"); + } PathBuf::from("voteJournal").join("votes.jsonl") } fn ensure_parent_dir(path: &Path) { - if let Some(parent) = path.parent() { let _ = fs::create_dir_all(parent); } + if let Some(parent) = path.parent() { + let _ = fs::create_dir_all(parent); + } } fn open_file_append(path: &Path) -> std::io::Result { @@ -68,7 +80,9 @@ impl VoteJournal { OpenOptions::new().create(true).append(true).open(path) } - fn open_file_read(path: &Path) -> std::io::Result { OpenOptions::new().read(true).open(path) } + fn open_file_read(path: &Path) -> std::io::Result { + OpenOptions::new().read(true).open(path) + } fn load_from_disk(path: &Path) -> VoteDataLru { let mut lru = VoteDataLru::new(MAX_RECENT_ENTRIES); @@ -78,13 +92,19 @@ impl VoteJournal { // Each line is expected to be a JSON-serialized VoteEnvelope let mut buf: Vec = Vec::with_capacity(MAX_RECENT_ENTRIES); for line in reader.lines().map_while(Result::ok) { - if line.is_empty() { continue; } + if line.is_empty() { + continue; + } if let Ok(env) = serde_json::from_str::(&line) { buf.push(env.data); - if buf.len() > MAX_RECENT_ENTRIES { buf.remove(0); } + if buf.len() > MAX_RECENT_ENTRIES { + buf.remove(0); + } } } - for vd in buf { lru.add(vd.target_number, vd); } + for vd in buf { + lru.add(vd.target_number, vd); + } } lru } @@ -98,9 +118,9 @@ impl VoteJournal { /// Returns true if the vote is allowed under rules, along with the provided source/target context. pub fn under_rules(&self, source_number: u64, target_number: u64) -> bool { // Rule 1: must not publish two distinct votes for the same height - if self.lru.contains(target_number) { + if self.lru.contains(target_number) { tracing::trace!(target: "bsc::vote", reason = "duplicate-height", target_number=target_number, "skip vote production"); - return false; + return false; } // Rule 2: must not vote within the span of its other votes @@ -111,9 +131,9 @@ impl VoteJournal { } while block_number < target_number { if let Some(vd) = self.lru.get(block_number) { - if vd.source_number > source_number { + if vd.source_number > source_number { tracing::trace!(target: "bsc::vote", reason = "backward-window", block_number=block_number, source_number=source_number, vd.source_number=vd.source_number, "skip vote production"); - return false; + return false; } } block_number += 1; @@ -123,9 +143,9 @@ impl VoteJournal { let upper = target_number + UPPER_LIMIT_OF_VOTE_BLOCK_NUMBER; while bn <= upper { if let Some(vd) = self.lru.get(bn) { - if vd.source_number < source_number { + if vd.source_number < source_number { tracing::trace!(target: "bsc::vote", reason = "forward-window", block_number=bn, source_number=source_number, vd.source_number=vd.source_number, "skip vote production"); - return false; + return false; } } bn += 1; @@ -160,10 +180,14 @@ static GLOBAL_JOURNAL: LazyLock> = LazyLock::new(|| { }); /// Get a guard to the global vote journal. -pub fn global() -> std::sync::MutexGuard<'static, VoteJournal> { GLOBAL_JOURNAL.lock().expect("vote journal poisoned") } +pub fn global() -> std::sync::MutexGuard<'static, VoteJournal> { + GLOBAL_JOURNAL.lock().expect("vote journal poisoned") +} /// Helper for external modules to check the rules via global journal. -pub fn under_rules(source_number: u64, target_number: u64) -> bool { global().under_rules(source_number, target_number) } +pub fn under_rules(source_number: u64, target_number: u64) -> bool { + global().under_rules(source_number, target_number) +} /// Helper for external modules to persist a signed vote via global journal. pub fn persist_vote(env: &VoteEnvelope) -> Result<(), String> { @@ -176,10 +200,8 @@ mod tests { use alloy_primitives::B256; fn tmp_path(name: &str) -> PathBuf { - let ts = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos(); + let ts = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos(); std::env::temp_dir().join(format!("{}_{}.jsonl", name, ts)) } @@ -187,7 +209,12 @@ mod tests { VoteEnvelope { vote_address: Default::default(), signature: Default::default(), - data: VoteData { source_number: src_n, source_hash: src_h, target_number: tgt_n, target_hash: tgt_h }, + data: VoteData { + source_number: src_n, + source_hash: src_h, + target_number: tgt_n, + target_hash: tgt_h, + }, } } diff --git a/src/system_contracts/mod.rs b/src/system_contracts/mod.rs index a5f5623c..171907be 100644 --- a/src/system_contracts/mod.rs +++ b/src/system_contracts/mod.rs @@ -1,11 +1,14 @@ #![allow(missing_docs)] //! Credits to use crate::{ - chainspec::{bsc::bsc_mainnet, bsc_chapel::bsc_testnet, bsc_rialto::bsc_qanet, bsc_rialto::RIALTO_CHAIN_ID}, + chainspec::{ + bsc::bsc_mainnet, bsc_chapel::bsc_testnet, bsc_rialto::bsc_qanet, + bsc_rialto::RIALTO_CHAIN_ID, + }, consensus::parlia::VoteAddress, hardforks::{bsc::BscHardfork, BscHardforks}, }; -use abi::{STAKE_HUB_ABI, VALIDATOR_SET_ABI, VALIDATOR_SET_ABI_BEFORE_LUBAN, SLASH_INDICATOR_ABI}; +use abi::{SLASH_INDICATOR_ABI, STAKE_HUB_ABI, VALIDATOR_SET_ABI, VALIDATOR_SET_ABI_BEFORE_LUBAN}; use alloy_chains::Chain; use alloy_consensus::TxLegacy; use alloy_dyn_abi::{DynSolValue, FunctionExt, JsonAbiExt}; @@ -65,7 +68,10 @@ impl SystemContract { } /// Return system address and input which is used to query current validators before luban. - pub fn get_current_validators_before_luban(&self, block_number: BlockNumber) -> (Address, Bytes) { + pub fn get_current_validators_before_luban( + &self, + block_number: BlockNumber, + ) -> (Address, Bytes) { let function = if self.chain_spec.is_euler_active_at_block(block_number) { self.validator_abi_before_luban .function("getMiningValidators") @@ -154,10 +160,7 @@ impl SystemContract { STAKE_HUB_CONTRACT, Bytes::from( function - .abi_encode_input(&[ - DynSolValue::from(offset), - DynSolValue::from(limit), - ]) + .abi_encode_input(&[DynSolValue::from(offset), DynSolValue::from(limit)]) .unwrap(), ), ) @@ -331,9 +334,7 @@ impl SystemContract { DynSolValue::FixedBytes(fb, 32) }) .collect(); - let input = function - .abi_encode_input(&[DynSolValue::Array(node_ids_values)]) - .unwrap(); + let input = function.abi_encode_input(&[DynSolValue::Array(node_ids_values)]).unwrap(); Transaction::Legacy(TxLegacy { chain_id: Some(self.chain_spec.chain().id()), @@ -360,9 +361,7 @@ impl SystemContract { DynSolValue::FixedBytes(fb, 32) }) .collect(); - let input = function - .abi_encode_input(&[DynSolValue::Array(node_ids_values)]) - .unwrap(); + let input = function.abi_encode_input(&[DynSolValue::Array(node_ids_values)]).unwrap(); Transaction::Legacy(TxLegacy { chain_id: Some(self.chain_spec.chain().id()), @@ -518,9 +517,7 @@ pub fn encode_add_node_ids_call(node_ids: Vec<[u8; 32]>) -> (Address, Bytes) { DynSolValue::FixedBytes(fb, 32) }) .collect(); - let input = function - .abi_encode_input(&[DynSolValue::Array(node_ids_values)]) - .unwrap(); + let input = function.abi_encode_input(&[DynSolValue::Array(node_ids_values)]).unwrap(); (STAKE_HUB_CONTRACT, Bytes::from(input)) } @@ -535,9 +532,7 @@ pub fn encode_remove_node_ids_call(node_ids: Vec<[u8; 32]>) -> (Address, Bytes) DynSolValue::FixedBytes(fb, 32) }) .collect(); - let input = function - .abi_encode_input(&[DynSolValue::Array(node_ids_values)]) - .unwrap(); + let input = function.abi_encode_input(&[DynSolValue::Array(node_ids_values)]).unwrap(); (STAKE_HUB_CONTRACT, Bytes::from(input)) } @@ -774,10 +769,10 @@ where } /// Get all system contracts to be upgraded. -/// +/// /// This function follows the exact upgrade order from Geth-BSC: /// https://github.com/bnb-chain/bsc/blob/master/core/systemcontracts/upgrade.go#L1078 -/// +/// /// The order is critical because: /// 1. Multiple hardforks may activate at the same block/timestamp /// 2. Later hardforks may upgrade the same contract addresses as earlier ones @@ -792,7 +787,7 @@ where ChainSpec: EthChainSpec + BscHardforks + Hardforks, { use tracing::trace; - + trace!( target: "bsc::system_contracts::upgrade", block_number, @@ -800,16 +795,16 @@ where parent_block_time, "get_upgrade_system_contracts called" ); - + let mut m = HashMap::new(); - + // Apply upgrades in the exact order as Geth-BSC upgradeBuildInSystemContract // Each hardfork upgrade will overwrite previous upgrades for the same address if spec.is_ramanujan_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Ramanujan.name()) { - for (address, v) in &contracts { - m.insert(*address, v.clone()); + for (address, v) in &contracts { + m.insert(*address, v.clone()); info!( target: "bsc::system_contracts::upgrade", block_number = block_number, @@ -821,7 +816,7 @@ where } } } - + if spec.is_niels_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Niels.name()) { for (address, v) in &contracts { @@ -837,7 +832,7 @@ where } } } - + if spec.is_mirror_sync_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::MirrorSync.name()) { for (address, v) in &contracts { @@ -853,7 +848,7 @@ where } } } - + if spec.is_bruno_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Bruno.name()) { for (address, v) in &contracts { @@ -869,7 +864,7 @@ where } } } - + if spec.is_euler_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Euler.name()) { for (address, v) in &contracts { @@ -885,7 +880,7 @@ where } } } - + if spec.is_gibbs_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Gibbs.name()) { for (address, v) in &contracts { @@ -901,7 +896,7 @@ where } } } - + if spec.is_moran_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Moran.name()) { for (address, v) in &contracts { @@ -917,7 +912,7 @@ where } } } - + if spec.is_planck_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Planck.name()) { for (address, v) in &contracts { @@ -933,7 +928,7 @@ where } } } - + if spec.is_luban_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Luban.name()) { for (address, v) in &contracts { @@ -949,7 +944,7 @@ where } } } - + if spec.is_plato_transition_at_block(block_number) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Plato.name()) { for (address, v) in &contracts { @@ -965,7 +960,7 @@ where } } } - + if spec.is_kepler_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Kepler.name()) { for (address, v) in &contracts { @@ -981,7 +976,7 @@ where } } } - + if spec.is_feynman_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Feynman.name()) { for (address, v) in &contracts { @@ -997,7 +992,7 @@ where } } } - + if spec.is_feynman_fix_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::FeynmanFix.name()) { for (address, v) in &contracts { @@ -1013,7 +1008,7 @@ where } } } - + if spec.is_haber_fix_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::HaberFix.name()) { for (address, v) in &contracts { @@ -1029,7 +1024,7 @@ where } } } - + if spec.is_bohr_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Bohr.name()) { for (address, v) in &contracts { @@ -1045,7 +1040,7 @@ where } } } - + if spec.is_pascal_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Pascal.name()) { for (address, v) in &contracts { @@ -1061,7 +1056,7 @@ where } } } - + if spec.is_lorentz_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Lorentz.name()) { for (address, v) in &contracts { @@ -1077,7 +1072,7 @@ where } } } - + if spec.is_maxwell_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Maxwell.name()) { for (address, v) in &contracts { @@ -1093,7 +1088,7 @@ where } } } - + if spec.is_fermi_transition_at_timestamp(block_number, block_time, parent_block_time) { if let Ok(contracts) = get_system_contract_codes(spec, BscHardfork::Fermi.name()) { for (address, v) in &contracts { @@ -1109,7 +1104,7 @@ where } } } - + Ok(m) } diff --git a/testing/genesis_local.json b/testing/genesis_local.json new file mode 100644 index 00000000..60e15fe9 --- /dev/null +++ b/testing/genesis_local.json @@ -0,0 +1,154 @@ +{ + "config": { + "chainId": 714, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "ramanujanBlock": 0, + "nielsBlock": 0, + "mirrorSyncBlock": 1, + "brunoBlock": 1, + "eulerBlock": 2, + "nanoBlock": 3, + "moranBlock": 3, + "gibbsBlock": 4, + "planckBlock": 5, + "lubanBlock": 6, + "platoBlock": 7, + "berlinBlock": 8, + "londonBlock": 8, + "hertzBlock": 8, + "hertzfixBlock": 8, + "shanghaiTime": 1773315539, + "keplerTime": 1773315539, + "feynmanTime": 1773315539, + "feynmanFixTime": 1773315539, + "cancunTime": 1773315539, + "haberTime": 1773315539, + "haberFixTime": 1773315539, + "bohrTime": 1773315539, + "pascalTime": 1773315539, + "pragueTime": 1773315539, + "lorentzTime": 1773315539, + "depositContractAddress": "0x0000000000000000000000000000000000000000", + "parlia": {}, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + } + }, + "tychoTime": 1773315539, + "maxwellTime": 1773315539, + "fermiTime": 1773315549, + "osakaTime": 1773315549, + "mendelTime": 1773315549 + }, + "nonce": "0x0", + "timestamp": "0x5e9da7ce", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000bcdd0d2cda5f6423e57b6a4dcd75decbe31aecf0bbd1acc20bd8304309d31d8fd235210d0efc049d5e2a531a825d8b61bcc305a35a7433e9a8920f0f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x8583b00", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE", + "alloc": { + "0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE": { + "balance": "0x0" + }, + "0x0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x6080604052600436106104405760003560e01c80638b5ad0c911610234578063c81b16621161012e578063e1c7392a116100b6578063f92eb86b1161007a578063f92eb86b14610b3f578063f9a2bbc714610b54578063fccc281314610b69578063fd4ad81f14610b7e578063fd6a687914610bad57610447565b8063e1c7392a14610ac2578063e40716a114610ad7578063ea321e4914610aec578063eb57e20214610b0c578063f340fa0114610b2c57610447565b8063d58918ae116100fd578063d58918ae14610a59578063d68fb56a14610a6e578063daacdb6614610a83578063dc927faf14610a98578063df8079e914610aad57610447565b8063c81b166214610a0f578063c8509d81146107e6578063cb75a59214610a24578063ce910b0c14610a3957610447565b8063aa82dce1116101bc578063aef198a911610180578063aef198a914610999578063b7ab4db5146109ae578063b8cf4ef1146109d0578063c466689d146109e5578063c6d33945146109fa57610447565b8063aa82dce11461090d578063aad5606314610922578063ab51bb9614610937578063ac43175114610959578063ad3c9da61461097957610447565b80639dc09262116102035780639dc09262146108a45780639fe0f816146108b9578063a1a11bf5146108ce578063a5422d5c146108e3578063a78abc16146108f857610447565b80638b5ad0c9146108455780638c5d749d1461085a5780638d19a4101461086f5780639369d7de1461088f57610447565b80634df6e0c3116103455780636e47b482116102cd578063820dcaa811610291578063820dcaa8146107d1578063831d65d1146107e6578063862498821461080657806388b32f111461081b5780638a7beb011461083057610447565b80636e47b4821461076857806375d47a0a1461077d57806378dfed4a146107925780637a84ca2a146107a75780637e434d54146107bc57610447565b806355614fcc1161031457806355614fcc146106c1578063565c56b3146106e157806360eba4fe1461070157806362b72cf5146107215780636969a25c1461073657610447565b80634df6e0c31461066d5780635192c82c1461068257806351b4dce31461069757806351e80672146106ac57610447565b80632a0ffb6e116103c857806335409f7f1161039757806335409f7f146105de5780633b071dcc146105fe57806343756e5c1461062157806345cf9daf14610636578063493279b11461064b57610447565b80632a0ffb6e1461055e578063300c35671461057e578063321d398a1461059e5780633365af3a146105be57610447565b8063152ad3b81161040f578063152ad3b8146104dd5780631bd14ed8146104ff5780631e4c1524146105145780631ff1806914610534578063280870281461054957610447565b806304c4fec61461044c57806307a56847146104635780630e2374a51461048e5780631182b875146104b057610447565b3661044757005b600080fd5b34801561045857600080fd5b50610461610bc2565b005b34801561046f57600080fd5b50610478610c36565b6040516104859190616e62565b60405180910390f35b34801561049a57600080fd5b506104a3610c3c565b6040516104859190616217565b3480156104bc57600080fd5b506104d06104cb3660046160fd565b610c42565b6040516104859190616337565b3480156104e957600080fd5b506104f2610d3d565b604051610485919061632c565b34801561050b57600080fd5b50610478610d46565b34801561052057600080fd5b5061046161052f366004615f2b565b610d4c565b34801561054057600080fd5b5061047861108f565b34801561055557600080fd5b506104a3611095565b34801561056a57600080fd5b50610461610579366004615e8b565b61109b565b34801561058a57600080fd5b50610461610599366004615ec3565b6110bc565b3480156105aa57600080fd5b506104f26105b93660046160aa565b611405565b3480156105ca57600080fd5b506104f26105d93660046160aa565b6114d4565b3480156105ea57600080fd5b506104616105f9366004615e8b565b611585565b34801561060a57600080fd5b506106136116ea565b6040516104859291906162bc565b34801561062d57600080fd5b506104a36119c6565b34801561064257600080fd5b506104786119cc565b34801561065757600080fd5b506106606119d2565b6040516104859190616e53565b34801561067957600080fd5b506106136119d8565b34801561068e57600080fd5b50610478611b72565b3480156106a357600080fd5b506104a3611b78565b3480156106b857600080fd5b506104a3611b7e565b3480156106cd57600080fd5b506104f26106dc366004615e8b565b611b84565b3480156106ed57600080fd5b506104786106fc366004615e8b565b611bc0565b34801561070d57600080fd5b506104d061071c3660046160aa565b611c11565b34801561072d57600080fd5b50610478611cb7565b34801561074257600080fd5b506107566107513660046160aa565b611cbd565b60405161048596959493929190616244565b34801561077457600080fd5b506104a3611d21565b34801561078957600080fd5b506104a3611d27565b34801561079e57600080fd5b50610478611d2d565b3480156107b357600080fd5b50610478611d33565b3480156107c857600080fd5b506104a3611d39565b3480156107dd57600080fd5b50610478611d3f565b3480156107f257600080fd5b506104616108013660046160fd565b611d45565b34801561081257600080fd5b50610478611d66565b34801561082757600080fd5b50610478611d6c565b34801561083c57600080fd5b506104f2611d72565b34801561085157600080fd5b50610478611d7b565b34801561086657600080fd5b50610478611d81565b34801561087b57600080fd5b5061047861088a366004615e8b565b611d9e565b34801561089b57600080fd5b50610461611dde565b3480156108b057600080fd5b506104a3611ef2565b3480156108c557600080fd5b50610478611ef8565b3480156108da57600080fd5b506104a3611efd565b3480156108ef57600080fd5b506104d0611f03565b34801561090457600080fd5b506104f2611f22565b34801561091957600080fd5b506104a3611f2b565b34801561092e57600080fd5b506104a3611f31565b34801561094357600080fd5b5061094c611f37565b6040516104859190616e95565b34801561096557600080fd5b5061046161097436600461604e565b611f3c565b34801561098557600080fd5b50610478610994366004615e8b565b6129a5565b3480156109a557600080fd5b506104786129b7565b3480156109ba57600080fd5b506109c36129c4565b60405161048591906162a9565b3480156109dc57600080fd5b50610478612aaf565b3480156109f157600080fd5b50610478612ab4565b348015610a0657600080fd5b50610478612aba565b348015610a1b57600080fd5b506104a3612abf565b348015610a3057600080fd5b50610478612ac5565b348015610a4557600080fd5b506104d0610a543660046160aa565b612acb565b348015610a6557600080fd5b50610478612ad8565b348015610a7a57600080fd5b50610478612ade565b348015610a8f57600080fd5b50610478612b1d565b348015610aa457600080fd5b506104a3612b23565b348015610ab957600080fd5b506104a3612b29565b348015610ace57600080fd5b50610461612b2f565b348015610ae357600080fd5b50610478612dc2565b348015610af857600080fd5b506104f2610b0736600461600f565b612dc8565b348015610b1857600080fd5b50610461610b27366004615e8b565b612f4e565b610461610b3a366004615e8b565b613056565b348015610b4b57600080fd5b5061047861340c565b348015610b6057600080fd5b506104a3613412565b348015610b7557600080fd5b506104a3613418565b348015610b8a57600080fd5b50610b9e610b993660046160aa565b61341e565b60405161048593929190616e6b565b348015610bb957600080fd5b506104a36134e0565b6000610bcd33611d9e565b9050600b8181548110610bdc57fe5b600091825260209091206001601690920201015460ff16610c185760405162461bcd60e51b8152600401610c0f90616b09565b60405180910390fd5b6000610c22612ade565b9050610c3133838360016134e6565b505050565b60095481565b61200181565b60005460609060ff16610c675760405162461bcd60e51b8152600401610c0f9061651c565b600b54610d2557610c76615a37565b60015460005b81811015610d2157600b8054600181018255600091909152835160008051602061709f83398151915260169092029182019081556020808601516000805160206170df8339815191528401805460ff1916911515919091179055604086015180518794610cfd936000805160206170bf833981519152909101920190615a66565b506060820151610d139060038301906013615ae0565b505050806001019050610c7c565b5050505b60405162461bcd60e51b8152600401610c0f9061676e565b60075460ff1681565b600f5481565b334114610d6b5760405162461bcd60e51b8152600401610c0f90616c6a565b3a15610d895760405162461bcd60e51b8152600401610c0f90616a48565b6107d0431015610d9857610c31565b8251604080518281526020808402820101909152606090828015610dd657816020015b610dc3615b0d565b815260200190600190039081610dbb5790505b50905060005b82811015610e80576040518060c00160405280878381518110610dfb57fe5b60200260200101516001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001868381518110610e3d57fe5b60200260200101516001600160401b031681526020016000151581526020016000815250828281518110610e6d57fe5b6020908102919091010152600101610ddc565b50606080610e8e83866136d8565b9150915060005b600154811015610f8457600060018281548110610eae57fe5b906000526020600020906004020160030154905080600014610f7b57600060018381548110610ed957fe5b9060005260206000209060040201600301819055506120026001600160a01b031663092193ab8260018581548110610f0d57fe5b60009182526020909120600491820201546040516001600160e01b031960e086901b168152610f48926001600160a01b039092169101616217565b6000604051808303818588803b158015610f6157600080fd5b505af1158015610f75573d6000803e3d6000fd5b50505050505b50600101610e95565b504715610ff2577f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d47604051610fba9190616e62565b60405180910390a1604051611002904780156108fc02916000818181858888f19350505050158015610ff0573d6000803e3d6000fd5b505b6000600355815115611008576110088282613bc2565b6110016001600160a01b031663fc4333cd6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561104557600080fd5b505af1158015611059573d6000803e3d6000fd5b50506040517fedd8d7296956dd970ab4de3f2fc03be2b0ffc615d20cd4c72c6e44f928630ebf925060009150a150505050505050565b60035481565b61200581565b3361200214610d255760405162461bcd60e51b8152600401610c0f90616e1c565b3341146110db5760405162461bcd60e51b8152600401610c0f90616c6a565b60105443116110fc5760405162461bcd60e51b8152600401610c0f90616698565b3a1561111a5760405162461bcd60e51b8152600401610c0f90616a48565b60005460ff1661113c5760405162461bcd60e51b8152600401610c0f9061651c565b60006110023168056bc75e2d631000008111156111735761116c8168056bc75e2d6310000063ffffffff6143b116565b915061117a565b50506113fb565b6040516309a99b4f60e41b815261100290639a99b4f0906111a1903090869060040161622b565b602060405180830381600087803b1580156111bb57600080fd5b505af11580156111cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f391906160c2565b9150816112015750506113fb565b6000805b8481101561122f5785858281811061121957fe5b9050602002013582019150806001019050611205565b508061123d575050506113fb565b6000806000805b898110156113f3578489898381811061125957fe5b9050602002013588028161126957fe5b0493508a8a8281811061127857fe5b905060200201602081019061128d9190615e8b565b6001600160a01b038116600090815260046020526040902054909350915081156113a95760006001808403815481106112c257fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff161561132f57836001600160a01b03167fb9c75cbbfde137c4281689580799ef5f52144e78858f776a5979b2b212137d85866040516113229190616e62565b60405180910390a26113a3565b600354611342908663ffffffff6143f316565b600390815581015461135a908663ffffffff6143f316565b60038201556040516001600160a01b038516907fcb0aad6cf9cd03bdf6137e359f541c42f38b39f007cae8e89e88aa7d8c6617b29061139a908890616e62565b60405180910390a25b506113eb565b826001600160a01b03167fb9c75cbbfde137c4281689580799ef5f52144e78858f776a5979b2b212137d85856040516113e29190616e62565b60405180910390a25b600101611244565b505050505050505b5050436010555050565b6001546000908210611419575060006114cf565b60006001600160a01b03166001838154811061143157fe5b60009182526020909120600490910201546001600160a01b03161480611461575060085415806114615750600a54155b80611470575060085460095410155b80611481575061147f826114d4565b155b806114aa57506000600b838154811061149657fe5b906000526020600020906016020160000154115b806114be575060016114ba6129c4565b5111155b156114cb575060006114cf565b5060015b919050565b60015460009082106114e8575060006114cf565b600b54821061152557600182815481106114fe57fe5b9060005260206000209060040201600201601c9054906101000a900460ff161590506114cf565b6001828154811061153257fe5b9060005260206000209060040201600201601c9054906101000a900460ff1615801561157f5750600b828154811061156657fe5b600091825260209091206001601690920201015460ff16155b92915050565b600b5461164357611594615a37565b60015460005b8181101561163f57600b8054600181018255600091909152835160008051602061709f83398151915260169092029182019081556020808601516000805160206170df8339815191528401805460ff191691151591909117905560408601518051879461161b936000805160206170bf833981519152909101920190615a66565b5060608201516116319060038301906013615ae0565b50505080600101905061159a565b5050505b336110011480611654575033612002145b6116705760405162461bcd60e51b8152600401610c0f90616553565b6001600160a01b0381166000908152600460205260409020548061169457506116e7565b6001810390506000600b82815481106116a957fe5b600091825260209091206001601690920201015460ff1690506116cc8383614418565b80156116d55750805b15610c31576009805460001901905550505b50565b60015460609081906000805b8281101561173d576001818154811061170b57fe5b9060005260206000209060040201600201601c9054906101000a900460ff16611735576001909101905b6001016116f6565b5060608160405190808252806020026020018201604052801561176a578160200160208202803683370190505b5090506060826040519080825280602002602001820160405280156117a357816020015b606081526020019060019003908161178e5790505b50600b546000945090915084141561191e5760005b8481101561191857600181815481106117cd57fe5b9060005260206000209060040201600201601c9054906101000a900460ff1661191057600181815481106117fd57fe5b600091825260209091206004909102015483516001600160a01b039091169084908690811061182857fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600b818154811061185557fe5b600091825260209182902060026016909202018101805460408051601f6000196101006001861615020190931694909404918201859004850284018501905280835291929091908301828280156118ed5780601f106118c2576101008083540402835291602001916118ed565b820191906000526020600020905b8154815290600101906020018083116118d057829003601f168201915b50505050508285815181106118fe57fe5b60209081029190910101526001909301925b6001016117b8565b506119ba565b60005b848110156119b8576001818154811061193657fe5b9060005260206000209060040201600201601c9054906101000a900460ff166119b0576001818154811061196657fe5b600091825260209091206004909102015483516001600160a01b039091169084908690811061199157fe5b6001600160a01b03909216602092830291909101909101526001909301925b600101611921565b505b909450925050505b9091565b61100181565b60085481565b6102ca81565b6060806000600e549050600080600c54116119f45760156119f8565b600c545b905060c86060611a066129c4565b90506060611a13826147db565b905083825111611a2b5790955093506119c292505050565b84848351031015611a3d578382510394505b8415611a7d576000834381611a4e57fe5b049050611a6383838389890360008b8b614949565b611a7b8383838989038a8a038b8c8c8b510301614949565b505b606084604051908082528060200260200182016040528015611aa9578160200160208202803683370190505b509050606085604051908082528060200260200182016040528015611ae257816020015b6060815260200190600190039081611acd5790505b50905060005b86811015611b6357848181518110611afc57fe5b6020026020010151838281518110611b1057fe5b60200260200101906001600160a01b031690816001600160a01b031681525050838181518110611b3c57fe5b6020026020010151828281518110611b5057fe5b6020908102919091010152600101611ae8565b50909750955050505050509091565b60065481565b61200681565b61200081565b6001600160a01b03811660009081526004602052604081205480611bac5760009150506114cf565b60001901611bb9816114d4565b9392505050565b6001600160a01b03811660009081526004602052604081205480611be85760009150506114cf565b600180820381548110611bf757fe5b906000526020600020906004020160030154915050919050565b60128181548110611c1e57fe5b600091825260209182902001805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815293509091830182828015611caf5780601f10611c8457610100808354040283529160200191611caf565b820191906000526020600020905b815481529060010190602001808311611c9257829003601f168201915b505050505081565b60105481565b60018181548110611cca57fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b0392831694509082169291821691600160a01b81046001600160401b031691600160e01b90910460ff169086565b61100581565b61100881565b6103e881565b600c5481565b61200381565b61271081565b3361200014610d255760405162461bcd60e51b8152600401610c0f90616c1b565b60025481565b60115481565b60145460ff1681565b600a5481565b600060175460001415611d9657506001611d9b565b506017545b90565b6001600160a01b03811660009081526004602052604081205480611dd45760405162461bcd60e51b8152600401610c0f90616ba3565b6000190192915050565b600b54611e9c57611ded615a37565b60015460005b81811015611e9857600b8054600181018255600091909152835160008051602061709f83398151915260169092029182019081556020808601516000805160206170df8339815191528401805460ff1916911515919091179055604086015180518794611e74936000805160206170bf833981519152909101920190615a66565b506060820151611e8a9060038301906013615ae0565b505050806001019050611df3565b5050505b600854611ea95760036008555b600a54611eb6576002600a555b6000611ec133611d9e565b9050611ecc81611405565b611ee85760405162461bcd60e51b8152600401610c0f906169c4565b6116e73382614aa0565b61100781565b600381565b61100681565b604051806101a001604052806101728152602001616f2d610172913981565b60005460ff1681565b61200281565b61300081565b600081565b60005460ff16611f5e5760405162461bcd60e51b8152600401610c0f9061651c565b3361100714611f7f5760405162461bcd60e51b8152600401610c0f90616a76565b611fdf84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260098152686275726e526174696f60b81b60208201529150614b389050565b1561209457602081146120045760405162461bcd60e51b8152600401610c0f9061637c565b604080516020601f840181900481028201810190925282815260009161204291858580838501838280828437600092019190915250614b9192505050565b905061271061206e601854612062600f54856143f390919063ffffffff16565b9063ffffffff6143f316565b111561208c5760405162461bcd60e51b8152600401610c0f90616792565b600655612962565b6120fe84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260138152726d61784e756d4f664d61696e7461696e696e6760681b60208201529150614b389050565b1561219857602081146121235760405162461bcd60e51b8152600401610c0f906163b3565b604080516020601f840181900481028201810190925282815260009161216191858580838501838280828437600092019190915250614b9192505050565b600c5490915080612170575060155b80821061218f5760405162461bcd60e51b8152600401610c0f906166da565b50600855612962565b61220184848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61696e7461696e536c6173685363616c6560701b60208201529150614b389050565b1561229a57602081146122265760405162461bcd60e51b8152600401610c0f906164a2565b604080516020601f840181900481028201810190925282815260009161226491858580838501838280828437600092019190915250614b9192505050565b90506000811180156122765750600a81105b6122925760405162461bcd60e51b8152600401610c0f90616cff565b600a55612962565b61230e84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601981527f6d61784e756d4f66576f726b696e6743616e646964617465730000000000000060208201529150614b389050565b1561239d57602081146123335760405162461bcd60e51b8152600401610c0f90616456565b604080516020601f840181900481028201810190925282815260009161237191858580838501838280828437600092019190915250614b9192505050565b9050600d548111156123955760405162461bcd60e51b8152600401610c0f9061689b565b600e55612962565b61240684848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260128152716d61784e756d4f6643616e6469646174657360701b60208201529150614b389050565b15612488576020811461242b5760405162461bcd60e51b8152600401610c0f90616ac4565b604080516020601f840181900481028201810190925282815260009161246991858580838501838280828437600092019190915250614b9192505050565b600d819055600e5490915081101561248257600d54600e555b50612962565b6124ec84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c6e756d4f66436162696e65747360981b60208201529150614b389050565b1561261157602081146125115760405162461bcd60e51b8152600401610c0f906164e7565b604080516020601f840181900481028201810190925282815260009161254f91858580838501838280828437600092019190915250614b9192505050565b9050600081116125715760405162461bcd60e51b8152600401610c0f90616650565b60006120026001600160a01b031663c473318f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125ae57600080fd5b505afa1580156125c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e691906160c2565b9050808211156126085760405162461bcd60e51b8152600401610c0f906163f9565b50600c55612962565b61267d84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601581527473797374656d52657761726442617365526174696f60581b60208201529150614b389050565b1561272657602081146126a25760405162461bcd60e51b8152600401610c0f90616cb7565b604080516020601f84018190048102820181019092528281526000916126e091858580838501838280828437600092019190915250614b9192505050565b9050612710612700601854612062600654856143f390919063ffffffff16565b111561271e5760405162461bcd60e51b8152600401610c0f906165c1565b600f55612962565b61279a84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601881527f73797374656d526577617264416e74694d4556526174696f000000000000000060208201529150614b389050565b1561284357602081146127bf5760405162461bcd60e51b8152600401610c0f90616821565b604080516020601f84018190048102820181019092528281526000916127fd91858580838501838280828437600092019190915250614b9192505050565b905061271061281d600f54612062600654856143f390919063ffffffff16565b111561283b5760405162461bcd60e51b8152600401610c0f90616935565b601855612962565b6128a484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600a8152690e8eae4dc98cadccee8d60b31b60208201529150614b389050565b1561294a57602081146128c95760405162461bcd60e51b8152600401610c0f90616737565b604080516020601f840181900481028201810190925282815260009161290791858580838501838280828437600092019190915250614b9192505050565b90506003811015801561291b575060408111155b806129265750806001145b6129425760405162461bcd60e51b8152600401610c0f90616d5c565b601755612962565b60405162461bcd60e51b8152600401610c0f90616dac565b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a84848484604051612997949392919061634a565b60405180910390a150505050565b60046020526000908152604090205481565b68056bc75e2d6310000081565b6001546060906000805b828110156129f3576129df816114d4565b156129eb578160010191505b6001016129ce565b50606081604051908082528060200260200182016040528015612a20578160200160208202803683370190505b5090506000915060005b83811015612aa757612a3b816114d4565b15612a9f5760018181548110612a4d57fe5b600091825260209091206004909102015482516001600160a01b0390911690839085908110612a7857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508260010192505b600101612a2a565b509250505090565b601581565b61027181565b600281565b61100281565b60175481565b60138181548110611c1e57fe5b60185481565b6000612ae86129c4565b519050600080600c5411612afd576015612b01565b600c545b905080821115612b0f578091505b81612b1957600191505b5090565b60055481565b61100381565b61200481565b60005460ff1615612b525760405162461bcd60e51b8152600401610c0f90616b35565b612b5a615b42565b6000612b80604051806101a001604052806101728152602001616f2d6101729139614b96565b9150915080612ba15760405162461bcd60e51b8152600401610c0f90616bda565b612ba9615a37565b60005b836020015151811015612daa57600b8054600181018255600091909152825160008051602061709f83398151915260169092029182019081556020808501516000805160206170df8339815191528401805460ff1916911515919091179055604085015180518694612c32936000805160206170bf833981519152909101920190615a66565b506060820151612c489060038301906013615ae0565b50505083604001518181518110612c5b57fe5b6020026020010151600b8281548110612c7057fe5b90600052602060002090601602016002019080519060200190612c94929190615a66565b50600184602001518281518110612ca757fe5b60209081029190910181015182546001818101855560009485528385208351600493840290910180546001600160a01b039283166001600160a01b03199182161782558587015182850180549185169183169190911790556040860151600283018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b199590981692909516919091179290921694909417161790915560a090930151600390930192909255918701518051918501939185908110612d7d57fe5b602090810291909101810151516001600160a01b0316825281019190915260400160002055600101612bac565b5050601060175550506000805460ff19166001179055565b600d5481565b601354600090815b81811015612ed157612eb985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050601380549092508591508110612e2157fe5b600091825260209182902001805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015612eaf5780601f10612e8457610100808354040283529160200191612eaf565b820191906000526020600020905b815481529060010190602001808311612e9257829003601f168201915b5050505050614d52565b15612ec95760019250505061157f565b600101612dd0565b5060125460005b81811015612f4257612f2986868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050601280549092508591508110612e2157fe5b15612f3a576001935050505061157f565b600101612ed8565b50600095945050505050565b3361100114612f6f5760405162461bcd60e51b8152600401610c0f90616dd3565b600b5461302d57612f7e615a37565b60015460005b8181101561302957600b8054600181018255600091909152835160008051602061709f83398151915260169092029182019081556020808601516000805160206170df8339815191528401805460ff1916911515919091179055604086015180518794613005936000805160206170bf833981519152909101920190615a66565b50606082015161301b9060038301906013615ae0565b505050806001019050612f84565b5050505b600061303882614db6565b905061304381611405565b15613052576130528282614aa0565b5050565b3341146130755760405162461bcd60e51b8152600401610c0f90616c6a565b60005460ff166130975760405162461bcd60e51b8152600401610c0f9061651c565b600034116130b75760405162461bcd60e51b8152600401610c0f9061686c565b3a156130d55760405162461bcd60e51b8152600401610c0f90616a48565b6001600160a01b03811660009081526004602052604090205460145434919060ff1661311557610271600f556103e86006556014805460ff191660011790555b600f54601754600110801561312c57506000601854115b1561315157600160175403601754438161314257fe5b06601854028161314e57fe5b04015b6000831180156131615750600081115b1561320e57600061318a61271061317e348563ffffffff614f3916565b9063ffffffff614f7316565b9050801561320c576040516110029082156108fc029083906000818181858888f193505050501580156131c1573d6000803e3d6000fd5b507f6ecc855f9440a9282c90913bbc91619fd44f5ec0b462af28d127b116f130aa4d816040516131f19190616e62565b60405180910390a1613209848263ffffffff6143b116565b93505b505b60008311801561322057506000600654115b156132c657600061324261271061317e60065434614f3990919063ffffffff16565b905080156132c45760405161dead9082156108fc029083906000818181858888f19350505050158015613279573d6000803e3d6000fd5b507f627059660ea01c4733a328effb2294d2f86905bf806da763a89cee254de8bee5816040516132a99190616e62565b60405180910390a16132c1848263ffffffff6143b116565b93505b505b81156133c45760006001808403815481106132dd57fe5b9060005260206000209060040201905080600201601c9054906101000a900460ff161561334a57846001600160a01b03167ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b48560405161333d9190616e62565b60405180910390a26133be565b60035461335d908563ffffffff6143f316565b6003908155810154613375908563ffffffff6143f316565b60038201556040516001600160a01b038616907f93a090ecc682c002995fad3c85b30c5651d7fd29b0be5da9d784a3302aedc055906133b5908790616e62565b60405180910390a25b50613406565b836001600160a01b03167ff177e5d6c5764d79c32883ed824111d9b13f5668cf6ab1cc12dd36791dd955b4846040516133fd9190616e62565b60405180910390a25b50505050565b600e5481565b61100081565b61dead81565b600b818154811061342b57fe5b6000918252602091829020601691909102018054600180830154600280850180546040805161010096831615969096026000190190911692909204601f810188900488028501880190925281845293965060ff909116949192918301828280156134d65780601f106134ab576101008083540402835291602001916134d6565b820191906000526020600020905b8154815290600101906020018083116134b957829003601f168201915b5050505050905083565b61100481565b6000600a54600014806134f7575082155b806135025750600954155b1561350f575060006136d0565b6009600081546001900391905081905550600061355a600a5461317e8661317e600b8a8154811061353c57fe5b6000918252602090912060169091020154439063ffffffff6143b116565b90506000600b868154811061356b57fe5b906000526020600020906016020160010160006101000a81548160ff0219169083151502179055506000806110016001600160a01b0316638256ace66040518163ffffffff1660e01b8152600401604080518083038186803b1580156135d057600080fd5b505afa1580156135e4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061360891906160da565b9150915060009350808310613686576136218888614418565b506040516328aa02b160e01b8152611001906328aa02b19061364b908b9087908a90600401616286565b600060405180830381600087803b15801561366557600080fd5b505af1158015613679573d6000803e3d6000fd5b5050505060019350613698565b8183106136985761369688614db6565b505b6040516001600160a01b038916907fb9d38178dc641ff1817967a63c9078cbcd955a9f1fcd75e0e3636de615d44d3b90600090a25050505b949350505050565b6060806000808080806136e9612ade565b6001549091505b801561391b57600181039250600b838154811061370957fe5b600091825260209091206001601690920201015460ff1661372957613912565b6001838154811061373657fe5b600091825260208220600490910201546001600160a01b03169550613760908690859085906134e6565b93508361376c57613912565b60405163436aa28360e11b81526000908190612002906386d5450690613796908a90600401616217565b60206040518083038186803b1580156137ae57600080fd5b505afa1580156137c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e69190615ea7565b90506001600160a01b0381161561386f576040516302ceee9160e11b81526120029063059ddd229061381c908490600401616217565b60206040518083038186803b15801561383457600080fd5b505afa158015613848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386c9190615ea7565b91505b60005b8c5181101561390e57876001600160a01b03168d828151811061389157fe5b6020026020010151600001516001600160a01b031614806138da5750826001600160a01b03168d82815181106138c357fe5b6020026020010151600001516001600160a01b0316145b156139065760018d82815181106138ed57fe5b602090810291909101015190151560809091015261390e565b600101613872565b5050505b600019016136f0565b5060005b89518110156139885789818151811061393457fe5b60200260200101516080015180613974575060006001600160a01b03168a828151811061395d57fe5b6020026020010151600001516001600160a01b0316145b15613980578560010195505b60010161391f565b5088518510613a705760408051600180825281830190925290816020015b6139ae615b0d565b8152602001906001900390816139a6575050604080516001808252818301909252919850602082015b60608152602001906001900390816139d7579050509550886000815181106139fb57fe5b602002602001015187600081518110613a1057fe5b602002602001018190525087600081518110613a2857fe5b602002602001015186600081518110613a3d57fe5b6020026020010181905250600087600081518110613a5757fe5b6020908102919091010151901515608090910152613bb5565b84895103604051908082528060200260200182016040528015613aad57816020015b613a9a615b0d565b815260200190600190039081613a925790505b50965084895103604051908082528060200260200182016040528015613ae757816020015b6060815260200190600190039081613ad25790505b5095506000915060005b8951811015613bb357898181518110613b0657fe5b602002602001015160800151158015613b49575060006001600160a01b03168a8281518110613b3157fe5b6020026020010151600001516001600160a01b031614155b15613bab57898181518110613b5a57fe5b6020026020010151888481518110613b6e57fe5b6020026020010181905250888181518110613b8557fe5b6020026020010151878481518110613b9957fe5b60200260200101819052508260010192505b600101613af1565b505b50505050505b9250929050565b600154825160005b82811015613cdf576001613bdc615b0d565b60018381548110613be957fe5b600091825260208083206040805160c08101825260049490940290910180546001600160a01b0390811685526001820154811693850193909352600281015492831691840191909152600160a01b82046001600160401b03166060840152600160e01b90910460ff16151560808301526003015460a082015291505b84811015613cb357878181518110613c7957fe5b6020026020010151600001516001600160a01b031682600001516001600160a01b03161415613cab5760009250613cb3565b600101613c65565b508115613cd55780516001600160a01b03166000908152600460205260408120555b5050600101613bca565b5080821115613d9e57805b82811015613d9c576001805480613cfd57fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b805480613d5057fe5b60008281526020812060166000199093019283020181815560018101805460ff1916905590613d826002830182615b66565b613d90600383016000615baa565b50509055600101613cea565b505b6000818310613dad5781613daf565b825b905060005b8181101561415357613e61868281518110613dcb57fe5b602002602001015160018381548110613de057fe5b60009182526020918290206040805160c08101825260049390930290910180546001600160a01b0390811684526001820154811694840194909452600281015493841691830191909152600160a01b83046001600160401b03166060830152600160e01b90920460ff161515608082015260039091015460a0820152614fb5565b614015578060010160046000888481518110613e7957fe5b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550858181518110613eb557fe5b602002602001015160018281548110613eca57fe5b6000918252602091829020835160049092020180546001600160a01b039283166001600160a01b0319918216178255928401516001820180549184169185169190911790556040840151600282018054606087015160808801511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909716929097169190911792909216939093171692909217905560a0909101516003909101558451859082908110613f8557fe5b6020026020010151600b8281548110613f9a57fe5b90600052602060002090601602016002019080519060200190613fbe929190615a66565b506000600b8281548110613fce57fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b805483908110613fff57fe5b600091825260209091206016909102015561414b565b85818151811061402157fe5b6020026020010151606001516001828154811061403a57fe5b906000526020600020906004020160020160146101000a8154816001600160401b0302191690836001600160401b0316021790555061410085828151811061407e57fe5b6020026020010151600b838154811061409357fe5b600091825260209182902060026016909202018101805460408051601f600019610100600186161502019093169490940491820185900485028401850190528083529192909190830182828015612eaf5780601f10612e8457610100808354040283529160200191612eaf565b61414b5784818151811061411057fe5b6020026020010151600b828154811061412557fe5b90600052602060002090601602016002019080519060200190614149929190615a66565b505b600101613db4565b508282111561432b57614164615a37565b835b838110156143285785818151811061417a57fe5b60200260200101518260400181905250600187828151811061419857fe5b6020908102919091018101518254600181810185556000948552838520835160049093020180546001600160a01b039384166001600160a01b0319918216178255848601518284018054918616918316919091179055604080860151600284018054606089015160808a01511515600160e01b0260ff60e01b196001600160401b03909216600160a01b0267ffffffffffffffff60a01b1995909a1692909616919091179290921696909617169190911790935560a090930151600390930192909255600b805492830181559093528451601690910260008051602061709f8339815191528101918255858301516000805160206170df8339815191528201805491151560ff19909216919091179055928501518051869492936142ce936000805160206170bf83398151915201920190615a66565b5060608201516142e49060038301906013615ae0565b50505080600101600460008984815181106142fb57fe5b602090810291909101810151516001600160a01b0316825281019190915260400160002055600101614166565b50505b614333615011565b61433b6151f3565b6000600981905560015493505b838110156143a9576000600b828154811061435f57fe5b60009182526020822060169190910201600101805460ff191692151592909217909155600b80548390811061439057fe5b6000918252602090912060169091020155600101614348565b505050505050565b6000611bb983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506153e1565b600082820183811015611bb95760405162461bcd60e51b8152600401610c0f9061658a565b6000806001838154811061442857fe5b906000526020600020906004020160030154905060006001808054905003905060016144526129c4565b51116144875760006001858154811061446757fe5b90600052602060002090600402016003018190555060009250505061157f565b846001600160a01b03167f3b6f9ef90462b512a1293ecec018670bf7b7f1876fb727590a8a6d7643130a70836040516144c09190616e62565b60405180910390a26001600160a01b038516600090815260046020526040812055835b600154600019018110156146ad576001816001018154811061450157fe5b90600052602060002090600402016001828154811061451c57fe5b60009182526020909120825460049092020180546001600160a01b03199081166001600160a01b0393841617825560018085015481840180548416918616919091179055600280860180549185018054909416919095161780835584546001600160401b03600160a01b91829004160267ffffffffffffffff60a01b1990911617808355935460ff600160e01b918290041615150260ff60e01b19909416939093179055600392830154920191909155600b8054909183019081106145dd57fe5b9060005260206000209060160201600b82815481106145f857fe5b600091825260209091208254601690920201908155600180830154818301805460ff909216151560ff199092169190911790556002808401805461464f938386019390821615610100026000190190911604615bb9565b5061466260038281019084016013615c2e565b5090505080600101600460006001848154811061467b57fe5b600091825260208083206004909202909101546001600160a01b031683528201929092526040019020556001016144e3565b5060018054806146b957fe5b60008281526020812060046000199093019283020180546001600160a01b0319908116825560018201805490911690556002810180546001600160e81b0319169055600301559055600b80548061470c57fe5b60008281526020812060166000199093019283020181815560018101805460ff191690559061473e6002830182615b66565b61474c600383016000615baa565b50509055600081838161475b57fe5b04905080156147cf5760015460005b818110156147cc576147a3836001838154811061478357fe5b9060005260206000209060040201600301546143f390919063ffffffff16565b600182815481106147b057fe5b600091825260209091206003600490920201015560010161476a565b50505b50600195945050505050565b60015481516040805182815260208084028201019091526060929190839082801561481a57816020015b60608152602001906001900390816148055790505b50600b5490915083146148315792506114cf915050565b60005b8281101561494057600b60016004600089858151811061485057fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054038154811061488457fe5b600091825260209182902060026016909202018101805460408051601f60001961010060018616150201909316949094049182018590048502840185019052808352919290919083018282801561491c5780601f106148f15761010080835404028352916020019161491c565b820191906000526020600020905b8154815290600101906020018083116148ff57829003601f168201915b505050505082828151811061492d57fe5b6020908102919091010152600101614834565b50949350505050565b60005b82811015614a96576000828783880160405160200161496c929190616209565b6040516020818303038152906040528051906020012060001c8161498c57fe5b06905080850182870114614a8d57600089838801815181106149aa57fe5b60200260200101519050606089848901815181106149c457fe5b602002602001015190508a838801815181106149dc57fe5b60200260200101518b858a01815181106149f257fe5b60200260200101906001600160a01b031690816001600160a01b031681525050818b84890181518110614a2157fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508983880181518110614a4f57fe5b60200260200101518a858a0181518110614a6557fe5b6020026020010181905250808a84890181518110614a7f57fe5b602002602001018190525050505b5060010161494c565b5050505050505050565b600980546001908101909155600b805483908110614aba57fe5b906000526020600020906016020160010160006101000a81548160ff02191690831515021790555043600b8281548110614af057fe5b600091825260208220601690910201919091556040516001600160a01b038416917ff62981a567ec3cec866c6fa93c55bcdf841d6292d18b8d522ececa769375d82d91a25050565b600081604051602001614b4b91906161ed565b6040516020818303038152906040528051906020012083604051602001614b7291906161ed565b6040516020818303038152906040528051906020012014905092915050565b015190565b614b9e615b42565b6000614ba8615b42565b614bb0615c58565b614bc1614bbc8661540d565b615432565b90506000805b614bd08361547c565b15614d445780614bf557614beb614be68461549d565b6154eb565b60ff168452614d3c565b8060011415614d37576060614c11614c0c8561549d565b61556b565b90508051604051908082528060200260200182016040528015614c4e57816020015b614c3b615b0d565b815260200190600190039081614c335790505b5085602001819052508051604051908082528060200260200182016040528015614c8c57816020015b6060815260200190600190039081614c775790505b50604086015260005b8151811015614d2c57614ca6615b0d565b60606000614cc6858581518110614cb957fe5b602002602001015161563c565b92509250925080614ce6578860009a509a50505050505050505050614d4d565b8289602001518581518110614cf757fe5b60200260200101819052508189604001518581518110614d1357fe5b6020026020010181905250505050806001019050614c95565b506001925050614d3c565b614d44565b600101614bc7565b50919350909150505b915091565b815181516000916001918114808314614d6e5760009250614dac565b600160208701838101602088015b600284838510011415614da7578051835114614d9b5760009650600093505b60209283019201614d7c565b505050505b5090949350505050565b6001600160a01b03811660009081526004602052604081205480614ddf575060001990506114cf565b600181039050600060018281548110614df457fe5b9060005260206000209060040201600301549050600060018381548110614e1757fe5b6000918252602090912060036004909202010155600154604051600019909101906001600160a01b038616907f8cd4e147d8af98a9e3b6724021b8bf6aed2e5dac71c38f2dce8161b82585b25d90614e70908590616e62565b60405180910390a280614e88578293505050506114cf565b6000818381614e9357fe5b0490508015614f2f5760005b84811015614ee157614eb8826001838154811061478357fe5b60018281548110614ec557fe5b6000918252602090912060036004909202010155600101614e9f565b50600180549085015b81811015614f2c57614f03836001838154811061478357fe5b60018281548110614f1057fe5b6000918252602090912060036004909202010155600101614eea565b50505b5091949350505050565b600082614f485750600061157f565b82820282848281614f5557fe5b0414611bb95760405162461bcd60e51b8152600401610c0f90616a07565b6000611bb983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250615756565b805182516000916001600160a01b039182169116148015614fef575081602001516001600160a01b031683602001516001600160a01b0316145b8015611bb95750506040908101519101516001600160a01b0390811691161490565b6012546013548082111561505c57805b8281101561505a57601280548061503457fe5b6001900381819060005260206000200160006150509190615b66565b9055600101615021565b505b600081831061506b578161506d565b825b905060005b818110156151855761512a6012828154811061508a57fe5b600091825260209182902001805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156151185780601f106150ed57610100808354040283529160200191615118565b820191906000526020600020905b8154815290600101906020018083116150fb57829003601f168201915b505050505060138381548110612e2157fe5b61517d576013818154811061513b57fe5b906000526020600020016012828154811061515257fe5b90600052602060002001908054600181600116156101000203166002900461517b929190615bb9565b505b600101615072565b5082821115610c3157825b82811015613406576012601382815481106151a757fe5b60009182526020808320845460018181018755958552919093209290910180546151ea949390920192909160026101009282161592909202600019011604615bb9565b50600101615190565b601354600b548082111561523e57805b8281101561523c57601380548061521657fe5b6001900381819060005260206000200160006152329190615b66565b9055600101615203565b505b600081831061524d578161524f565b825b905060005b8181101561536e5761530c6013828154811061526c57fe5b600091825260209182902001805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156152fa5780601f106152cf576101008083540402835291602001916152fa565b820191906000526020600020905b8154815290600101906020018083116152dd57829003601f168201915b5050505050600b838154811061409357fe5b61536657600b818154811061531d57fe5b90600052602060002090601602016002016013828154811061533b57fe5b906000526020600020019080546001816001161561010002031660029004615364929190615bb9565b505b600101615254565b5082821115610c3157825b82811015613406576013600b828154811061539057fe5b6000918252602080832084546001808201875595855291909320601692909202909201600290810180546153d895939094019390926000199082161561010002011604615bb9565b50600101615379565b600081848411156154055760405162461bcd60e51b8152600401610c0f9190616337565b505050900390565b615415615c78565b506040805180820190915281518152602082810190820152919050565b61543a615c58565b6154438261578d565b61544c57600080fd5b600061545b83602001516157c7565b60208085015160408051808201909152868152920190820152915050919050565b6000615486615c78565b505080518051602091820151919092015191011190565b6154a5615c78565b6154ae8261547c565b6154b757600080fd5b602082015160006154c78261582a565b80830160209586015260408051808201909152908152938401919091525090919050565b80516000901580159061550057508151602110155b61550957600080fd5b600061551883602001516157c7565b9050808360000151101561553e5760405162461bcd60e51b8152600401610c0f90616b6c565b82516020808501518301805192849003929183101561494057506020919091036101000a90049392505050565b60606155768261578d565b61557f57600080fd5b600061558a8361590b565b90506060816040519080825280602002602001820160405280156155c857816020015b6155b5615c78565b8152602001906001900390816155ad5790505b50905060006155da85602001516157c7565b60208601510190506000805b84811015615631576155f78361582a565b915060405180604001604052808381526020018481525084828151811061561a57fe5b6020908102919091010152918101916001016155e6565b509195945050505050565b615644615b0d565b60606000615650615b0d565b606061565a615c58565b61566387615432565b90506000805b6156728361547c565b15615747578061569d5761568d6156888461549d565b615967565b6001600160a01b0316855261573f565b80600114156156c5576156b26156888461549d565b6001600160a01b0316602086015261573f565b80600214156156ed576156da6156888461549d565b6001600160a01b0316604086015261573f565b806003141561571957615702614be68461549d565b6001600160401b031660608601526001915061573f565b806004141561573a5761573361572e8461549d565b615981565b935061573f565b615747565b600101615669565b50929791965091945092505050565b600081836157775760405162461bcd60e51b8152600401610c0f9190616337565b50600083858161578357fe5b0495945050505050565b805160009061579e575060006114cf565b6020820151805160001a9060c08210156157bd576000925050506114cf565b5060019392505050565b8051600090811a60808110156157e15760009150506114cf565b60b88110806157fc575060c081108015906157fc575060f881105b1561580b5760019150506114cf565b60c081101561581f5760b5190190506114cf565b60f5190190506114cf565b80516000908190811a60808110156158455760019150615904565b60b881101561585a57607e1981019150615904565b60c08110156158ab57600060b78203600186019550806020036101000a8651049150600181018201935050808310156158a55760405162461bcd60e51b8152600401610c0f9061690a565b50615904565b60f88110156158c05760be1981019150615904565b600060f78203600186019550806020036101000a8651049150600181018201935050808310156159025760405162461bcd60e51b8152600401610c0f9061690a565b505b5092915050565b805160009061591c575060006114cf565b6000809050600061593084602001516157c7565b602085015185519181019250015b8082101561595e5761594f8261582a565b8201915082600101925061593e565b50909392505050565b805160009060151461597857600080fd5b61157f826154eb565b805160609061598f57600080fd5b600061599e83602001516157c7565b83516040805191839003808352601f19601f82011683016020019091529192506060908280156159d5576020820181803683370190505b5090506000816020019050614940848760200151018285806159f657610c31565b5b60208110615a16578251825260209283019290910190601f19016159f7565b915181516020939093036101000a6000190180199091169216919091179052565b60405180608001604052806000815260200160001515815260200160608152602001615a61615c92565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615aa757805160ff1916838001178555615ad4565b82800160010185558215615ad4579182015b82811115615ad4578251825591602001919060010190615ab9565b50612b19929150615cb1565b8260138101928215615ad45791602002820182811115615ad4578251825591602001919060010190615ab9565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6040518060600160405280600060ff16815260200160608152602001606081525090565b50805460018160011615610100020316600290046000825580601f10615b8c57506116e7565b601f0160209004906000526020600020908101906116e79190615cb1565b506116e7906013810190615cb1565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10615bf25780548555615ad4565b82800160010185558215615ad457600052602060002091601f016020900482015b82811115615ad4578254825591600101919060010190615c13565b8260138101928215615ad45791820182811115615ad4578254825591600101919060010190615c13565b6040518060400160405280615c6b615c78565b8152602001600081525090565b604051806040016040528060008152602001600081525090565b6040518061026001604052806013906020820280368337509192915050565b611d9b91905b80821115612b195760008155600101615cb7565b803561157f81616f17565b60008083601f840112615ce7578182fd5b5081356001600160401b03811115615cfd578182fd5b6020830191508360208083028501011115613bbb57600080fd5b6000601f8381840112615d28578182fd5b8235615d3b615d3682616ecc565b616ea6565b818152925060208084019085810160005b84811015615dcd578135880189603f820112615d6757600080fd5b838101356001600160401b03811115615d7f57600080fd5b615d90818901601f19168601616ea6565b81815260408c81848601011115615da657600080fd5b82818501888401375060009181018601919091528552509282019290820190600101615d4c565b50505050505092915050565b600082601f830112615de9578081fd5b8135615df7615d3682616ecc565b818152915060208083019084810181840286018201871015615e1857600080fd5b6000805b85811015615dcd5782356001600160401b0381168114615e3a578283fd5b85529383019391830191600101615e1c565b60008083601f840112615e5d578182fd5b5081356001600160401b03811115615e73578182fd5b602083019150836020828501011115613bbb57600080fd5b600060208284031215615e9c578081fd5b8135611bb981616f17565b600060208284031215615eb8578081fd5b8151611bb981616f17565b60008060008060408587031215615ed8578283fd5b84356001600160401b0380821115615eee578485fd5b615efa88838901615cd6565b90965094506020870135915080821115615f12578384fd5b50615f1f87828801615cd6565b95989497509550505050565b600080600060608486031215615f3f578283fd5b83356001600160401b0380821115615f55578485fd5b81860187601f820112615f66578586fd5b80359250615f76615d3684616ecc565b80848252602080830192508084018b828389028701011115615f9657898afd5b8994505b86851015615fc057615fac8c82615ccb565b845260019490940193928101928101615f9a565b509097508801359350505080821115615fd7578384fd5b615fe387838801615dd9565b93506040860135915080821115615ff8578283fd5b5061600586828701615d17565b9150509250925092565b60008060208385031215616021578182fd5b82356001600160401b03811115616036578283fd5b61604285828601615e4c565b90969095509350505050565b60008060008060408587031215616063578384fd5b84356001600160401b0380821115616079578586fd5b61608588838901615e4c565b9096509450602087013591508082111561609d578384fd5b50615f1f87828801615e4c565b6000602082840312156160bb578081fd5b5035919050565b6000602082840312156160d3578081fd5b5051919050565b600080604083850312156160ec578182fd5b505080516020909101519092909150565b600080600060408486031215616111578081fd5b833560ff81168114616121578182fd5b925060208401356001600160401b0381111561613b578182fd5b61614786828701615e4c565b9497909650939450505050565b6000815180845260208085019450808401835b8381101561618c5781516001600160a01b031687529582019590820190600101616167565b509495945050505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b600081518084526161d9816020860160208601616eeb565b601f01601f19169290920160200192915050565b600082516161ff818460208701616eeb565b9190910192915050565b918252602082015260400190565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03968716815294861660208601529290941660408401526001600160401b03166060830152911515608082015260a081019190915260c00190565b6001600160a01b0393909316835260208301919091521515604082015260600190565b600060208252611bb96020830184616154565b6000604082526162cf6040830185616154565b602083820381850152818551808452828401915082838202850101838801865b8381101561631d57601f1987840301855261630b8383516161c1565b948601949250908501906001016162ef565b50909998505050505050505050565b901515815260200190565b600060208252611bb960208301846161c1565b60006040825261635e604083018688616197565b8281036020840152616371818587616197565b979650505050505050565b6020808252601c908201527f6c656e677468206f66206275726e526174696f206d69736d6174636800000000604082015260600190565b60208082526026908201527f6c656e677468206f66206d61784e756d4f664d61696e7461696e696e67206d696040820152650e6dac2e8c6d60d31b606082015260800190565b60208082526038908201527f746865206e756d4f66436162696e657473206d757374206265206c657373207460408201527f68616e206d6178456c656374656456616c696461746f72730000000000000000606082015260800190565b6020808252602c908201527f6c656e677468206f66206d61784e756d4f66576f726b696e6743616e6469646160408201526b0e8cae640dad2e6dac2e8c6d60a31b606082015260800190565b60208082526025908201527f6c656e677468206f66206d61696e7461696e536c6173685363616c65206d69736040820152640dac2e8c6d60db1b606082015260800190565b6020808252818101527f6c656e677468206f66206e756d4f66436162696e657473206d69736d61746368604082015260600190565b60208082526019908201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604082015260600190565b6020808252601f908201527f6f6e6c7920736c617368206f72207374616b6548756220636f6e747261637400604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526063908201527f7468652073797374656d52657761726442617365526174696f20706c7573206260408201527f75726e526174696f20616e642073797374656d526577617264416e74694d455660608201527f526174696f206d757374206265206e6f2067726561746572207468616e20313060808201526203030360ec1b60a082015260c00190565b60208082526028908201527f746865206e756d4f66436162696e657473206d75737420626520677265617465604082015267072207468616e20360c41b606082015260800190565b60208082526022908201527f63616e206e6f7420646f207468697320747769636520696e206f6e6520626c6f604082015261636b60f01b606082015260800190565b60208082526037908201527f746865206d61784e756d4f664d61696e7461696e696e67206d7573742062652060408201527f6c657373207468616e206e756d4f66436162696e657473000000000000000000606082015260800190565b6020808252601d908201527f6c656e677468206f66207475726e4c656e677468206d69736d61746368000000604082015260600190565b6020808252600a908201526919195c1c9958d85d195960b21b604082015260600190565b60208082526063908201527f746865206275726e526174696f20706c75732073797374656d5265776172644260408201527f617365526174696f20616e642073797374656d526577617264416e74694d455660608201527f526174696f206d757374206265206e6f2067726561746572207468616e20313060808201526203030360ec1b60a082015260c00190565b6020808252602b908201527f6c656e677468206f662073797374656d526577617264416e74694d455652617460408201526a0d2de40dad2e6dac2e8c6d60ab1b606082015260800190565b6020808252601590820152746465706f7369742076616c7565206973207a65726f60581b604082015260600190565b60208082526049908201527f746865206d61784e756d4f66576f726b696e6743616e64696461746573206d7560408201527f7374206265206e6f742067726561746572207468616e206d61784e756d4f6643606082015268616e6469646174657360b81b608082015260a00190565b6020808252601190820152706164646974696f6e206f766572666c6f7760781b604082015260600190565b60208082526063908201527f7468652073797374656d526577617264416e74694d4556526174696f20706c7560408201527f73206275726e526174696f20616e642073797374656d5265776172644261736560608201527f526174696f206d757374206265206e6f2067726561746572207468616e20313060808201526203030360ec1b60a082015260c00190565b60208082526023908201527f63616e206e6f7420656e7465722054656d706f72617279204d61696e74656e616040820152626e636560e81b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601490820152736761737072696365206973206e6f74207a65726f60601b604082015260600190565b6020808252602e908201527f746865206d6573736167652073656e646572206d75737420626520676f76657260408201526d1b985b98d94818dbdb9d1c9858dd60921b606082015260800190565b60208082526025908201527f6c656e677468206f66206d61784e756d4f6643616e64696461746573206d69736040820152640dac2e8c6d60db1b606082015260800190565b6020808252601290820152716e6f7420696e206d61696e74656e616e636560701b604082015260600190565b60208082526019908201527f74686520636f6e747261637420616c726561647920696e697400000000000000604082015260600190565b6020808252601a908201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604082015260600190565b60208082526017908201527f6f6e6c792063757272656e742076616c696461746f7273000000000000000000604082015260600190565b60208082526021908201527f6661696c656420746f20706172736520696e69742076616c696461746f7253656040820152601d60fa1b606082015260800190565b6020808252602f908201527f746865206d6573736167652073656e646572206d7573742062652063726f737360408201526e0818da185a5b8818dbdb9d1c9858dd608a1b606082015260800190565b6020808252602d908201527f746865206d6573736167652073656e646572206d75737420626520746865206260408201526c3637b1b590383937b23ab1b2b960991b606082015260800190565b60208082526028908201527f6c656e677468206f662073797374656d52657761726442617365526174696f206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b6020808252603e908201527f746865206d61696e7461696e536c6173685363616c65206d757374206265206760408201527f726561746572207468616e203020616e64206c657373207468616e2031300000606082015260800190565b60208082526030908201527f746865207475726e4c656e6774682073686f756c6420626520696e205b332c3660408201526f345d206f7220657175616c20746f203160801b606082015260800190565b6020808252600d908201526c756e6b6e6f776e20706172616d60981b604082015260600190565b60208082526029908201527f746865206d6573736167652073656e646572206d75737420626520736c6173686040820152680818dbdb9d1c9858dd60ba1b606082015260800190565b6020808252601f908201527f746865206d73672073656e646572206d757374206265207374616b6548756200604082015260600190565b61ffff91909116815260200190565b90815260200190565b6000848252831515602083015260606040830152616e8c60608301846161c1565b95945050505050565b63ffffffff91909116815260200190565b6040518181016001600160401b0381118282101715616ec457600080fd5b604052919050565b60006001600160401b03821115616ee1578081fd5b5060209081020190565b60005b83811015616f06578181015183820152602001616eee565b838111156134065750506000910152565b6001600160a01b03811681146116e757600080fdfef9016f80f9016bf87794bcdd0d2cda5f6423e57b6a4dcd75decbe31aecf094bcdd0d2cda5f6423e57b6a4dcd75decbe31aecf094bcdd0d2cda5f6423e57b6a4dcd75decbe31aecf08601d1a94a2000b0b3baf71dc234890671fc3292afde45e20ce83cb8cd65c614be9fa29932c34051a75cbc1e25b968cc72142c91a56b521af87794bbd1acc20bd8304309d31d8fd235210d0efc049d94bbd1acc20bd8304309d31d8fd235210d0efc049d94bbd1acc20bd8304309d31d8fd235210d0efc049d8601d1a94a2000b08f124155128c0f4ff8c2b0803c3390bf672e6d26480af4f9648b8d2214d642a6dc2c25c9a37ccc576766e5838d71f52af877945e2a531a825d8b61bcc305a35a7433e9a8920f0f945e2a531a825d8b61bcc305a35a7433e9a8920f0f945e2a531a825d8b61bcc305a35a7433e9a8920f0f8601d1a94a2000b0a42d8fd0af73dc1c2a0238545985c0dba04fd57bc2f66573c86cfbb9f2a3cd5c10d6ddb6a588500ef80f2f5b56b8a21b0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbaa164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b506004361061028a5760003560e01c80638256ace61161015c578063c80d4b8f116100ce578063dcc6f15611610087578063dcc6f156146104b6578063df8079e9146104be578063e1c7392a146104c6578063f9a2bbc7146104ce578063fc4333cd146104d6578063fd6a6879146104de5761028a565b8063c80d4b8f14610478578063c81b166214610480578063c8509d8114610405578063c96be4cb14610488578063cc844b731461049b578063dc927faf146104ae5761028a565b8063a78abc1611610120578063a78abc1614610430578063aa82dce114610438578063aad5606314610440578063ab51bb9614610448578063ac0af6291461045d578063ac431751146104655761028a565b80638256ace6146103fd578063831d65d1146104055780639dc09262146104185780639f804f5f14610420578063a1a11bf5146104285761028a565b806343756e5c116102005780635bfb4990116101b95780635bfb4990146103c257806362b72cf5146103d55780636e47b482146103dd57806375d47a0a146103e55780637912a65d146103ed5780637e434d54146103f55761028a565b806343756e5c14610385578063493279b11461038d57806350055f90146103a257806351b4dce3146103aa57806351e80672146103b2578063567a372d146103ba5761028a565b80632808702811610252578063280870281461031957806328aa02b1146103215780633306ccca1461033457806335aa2e441461034957806337c8dab91461035c578063389f4f711461037d5761028a565b80630e2374a51461028f5780631182b875146102ad57806322d1e80b146102cd57806323bac5a2146102e25780632796211814610304575b600080fd5b6102976104e6565b6040516102a49190612b34565b60405180910390f35b6102c06102bb366004612a4d565b6104ec565b6040516102a49190612b6c565b6102d5610552565b6040516102a49190612b61565b6102f56102f0366004612752565b61055b565b6040516102a4939291906132cf565b6103176103123660046128aa565b61057e565b005b6102976108d3565b61031761032f36600461278a565b6108d9565b61033c61090a565b6040516102a49190613297565b610297610357366004612a1d565b61090f565b61036f61036a366004612752565b610936565b6040516102a49291906132c1565b61033c61098d565b610297610993565b610395610999565b6040516102a49190613288565b61033c61099f565b6102976109a5565b6102976109ab565b61033c6109b1565b6103176103d0366004612752565b6109b7565b61033c610a3f565b610297610a45565b610297610a4b565b61033c610a51565b610297610a56565b61036f610a5c565b610317610413366004612a4d565b610a66565b610297610a87565b61033c610a8d565b610297610a93565b6102d5610a99565b610297610aa2565b610297610aa8565b610450610aae565b6040516102a491906132e7565b61033c610ab3565b610317610473366004612901565b610ab8565b61033c611054565b610297611059565b610317610496366004612752565b61105f565b6103176104a936600461296a565b61137c565b61029761181a565b61033c611820565b610297611825565b61031761182b565b610297611877565b61031761187d565b610297611cc6565b61200181565b606033612000146105185760405162461bcd60e51b815260040161050f90613162565b60405180910390fd5b60005460ff1661053a5760405162461bcd60e51b815260040161050f90612c58565b60405162461bcd60e51b815260040161050f90612e27565b60075460ff1681565b600260208190526000918252604090912080546001820154919092015460ff1683565b60005460ff166105a05760405162461bcd60e51b815260040161050f90612c58565b6006546105ad5760146006555b6008546105ba57603c6008555b8151158015906105ca5750805115155b6105e65760405162461bcd60e51b815260040161050f906130f7565b60408051600380825260808201909252606091816020015b60608152602001906001900390816105fe5790505090506106206102ca611ccc565b8160008151811061062d57fe5b602002602001018190525061064183611ce7565b8160018151811061064e57fe5b602002602001018190525061066282611ce7565b8160028151811061066f57fe5b6020026020010181905250606061068582611d3d565b60408051603480825260608281019093529293509091602082018180368337019050509050815160346020830182602086016068600019fa6106c657600080fd5b506014810151603482015160405163436aa28360e11b8152600090612002906386d54506906106f9908690600401612b34565b60206040518083038186803b15801561071157600080fd5b505afa158015610725573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610749919061276e565b6001600160a01b031614156107705760405162461bcd60e51b815260040161050f90612c28565b43600854820110156107945760405162461bcd60e51b815260040161050f90612bc9565b604051631871f7d960e31b81526120029063c38fbec8906107b9908590600401612b34565b600060405180830381600087803b1580156107d357600080fd5b505af11580156107e7573d6000803e3d6000fd5b50506040516335409f7f60e01b815261100092506335409f7f9150610810908590600401612b34565b600060405180830381600087803b15801561082a57600080fd5b505af115801561083e573d6000803e3d6000fd5b50506006546040516309a99b4f60e41b815260646110028031909302049350909150639a99b4f0906108769033908590600401612b48565b602060405180830381600087803b15801561089057600080fd5b505af11580156108a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c89190612a35565b505050505050505050565b61200581565b33611000146108fa5760405162461bcd60e51b815260040161050f90612ead565b610905838383611dce565b505050565b603c81565b6001818154811061091c57fe5b6000918252602090912001546001600160a01b0316905081565b600080610941612585565b5050506001600160a01b0316600090815260026020818152604092839020835160608101855281548082526001830154938201849052919093015460ff16151592909301919091529091565b60055481565b61100181565b6102ca81565b60065481565b61200681565b61200081565b60045481565b33611000146109d85760405162461bcd60e51b815260040161050f90612ead565b60005460ff166109fa5760405162461bcd60e51b815260040161050f90612c58565b806001600160a01b03167fd7bc86ff5d08c8ab043edec743302aba2520e6635172a428bc956721db9e2d1c6000604051610a349190612b7f565b60405180910390a250565b60035481565b61100581565b61100881565b603281565b61200381565b6004546005549091565b33612000146105185760405162461bcd60e51b815260040161050f90613162565b61100781565b60085481565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b600481565b60005460ff16610ada5760405162461bcd60e51b815260040161050f90612c58565b3361100714610afb5760405162461bcd60e51b815260040161050f90612fe6565b610b6684848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260148152731b5a5cd9195b59585b9bdc951a1c995cda1bdb1960621b602082015291506120079050565b15610c015760208114610b8b5760405162461bcd60e51b815260040161050f90612e39565b604080516020601f8401819004810282018101909252828152600091610bc99185858083850183828082843760009201919091525061206192505050565b905060018110158015610bdd575060055481105b610bf95760405162461bcd60e51b815260040161050f9061311d565b600455611011565b610c6784848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600f81526e19995b1bdb9e551a1c995cda1bdb19608a1b602082015291506120079050565b15610d035760208114610c8c5760405162461bcd60e51b815260040161050f90613034565b604080516020601f8401819004810282018101909252828152600091610cca9185858083850183828082843760009201919091525061206192505050565b90506103e88111158015610cdf575060045481115b610cfb5760405162461bcd60e51b815260040161050f90612d11565b600555611011565b610d7084848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601681527566656c6f6e79536c617368526577617264526174696f60501b602082015291506120079050565b15610e0a5760208114610d955760405162461bcd60e51b815260040161050f90612f6e565b604080516020601f8401819004810282018101909252828152600091610dd39185858083850183828082843760009201919091525061206192505050565b9050600a8110158015610de65750606481105b610e025760405162461bcd60e51b815260040161050f90613076565b600655611011565b610e7e84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601881527f656e61626c654d616c6963696f7573566f7465536c6173680000000000000000602082015291506120079050565b15610ef55760208114610ea35760405162461bcd60e51b815260040161050f90612d46565b604080516020601f8401819004810282018101909252828152610edf919084848083850183828082843760009201919091525061206692505050565b6007805460ff1916911515919091179055611011565b610f5c84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152601081526f66656c6f6e79536c61736853636f706560801b602082015291506120079050565b15610ff95760208114610f815760405162461bcd60e51b815260040161050f90612efd565b604080516020601f8401819004810282018101909252828152600091610fbf9185858083850183828082843760009201919091525061206192505050565b90506170808110158015610fd55750620d2f0081105b610ff15760405162461bcd60e51b815260040161050f90612c8f565b600855611011565b60405162461bcd60e51b815260040161050f906131fe565b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040516110469493929190612b97565b60405180910390a150505050565b609681565b61100281565b33411461107e5760405162461bcd60e51b815260040161050f906131b1565b60005460ff166110a05760405162461bcd60e51b815260040161050f90612c58565b60035443116110c15760405162461bcd60e51b815260040161050f90613253565b3a156110df5760405162461bcd60e51b815260040161050f90612f40565b60405163155853f360e21b8152611000906355614fcc90611104908490600401612b34565b60206040518083038186803b15801561111c57600080fd5b505afa158015611130573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611154919061288e565b61115d57611375565b611165612585565b506001600160a01b0381166000908152600260208181526040928390208351606081018552815481526001820154928101929092529091015460ff1615801592820192909252906111c0576020810180516001019052611219565b60016040820181905260208201819052805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b0384161790555b43815260055460208201518161122b57fe5b066112a357600060208201526040516335409f7f60e01b8152611000906335409f7f9061125c908590600401612b34565b600060405180830381600087803b15801561127657600080fd5b505af115801561128a573d6000803e3d6000fd5b5050505061129e8282602001516000611dce565b61130f565b6004548160200151816112b257fe5b0661130f576040516375abf10160e11b81526110009063eb57e202906112dc908590600401612b34565b600060405180830381600087803b1580156112f657600080fd5b505af115801561130a573d6000803e3d6000fd5b505050505b6001600160a01b0382166000818152600260208181526040808420865181559186015160018301558581015191909201805460ff1916911515919091179055517fddb6012116e51abf5436d956a4f0ebd927e92c576ff96d7918290c8782291e3e9190a2505b5043600355565b60005460ff1661139e5760405162461bcd60e51b815260040161050f90612c58565b60075460ff166113c05760405162461bcd60e51b815260040161050f90612bf3565b6006546113cd5760146006555b6008546113da57603c6008555b6008548151604001514391011180156113fe57504360085482602001516040015101115b61141a5760405162461bcd60e51b815260040161050f90613225565b8060200151602001518160000151602001511480156114485750806020015160600151816000015160600151145b156114655760405162461bcd60e51b815260040161050f90612e80565b8051604081015190511080156114845750602081015160408101519051105b6114a05760405162461bcd60e51b815260040161050f90612df0565b6020810151518151511080156114c55750806000015160400151816020015160400151105b806114f057508051516020820151511080156114f05750806020015160400151816000015160400151105b8061150a5750806020015160400151816000015160400151145b6115265760405162461bcd60e51b815260040161050f90612cda565b604080820151905163ea321e4960e01b81526110009163ea321e499161154f9190600401612b6c565b60206040518083038186803b15801561156757600080fd5b505afa15801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f919061288e565b6115bb5760405162461bcd60e51b815260040161050f90612fb7565b6115cd8160000151826040015161208e565b80156115e657506115e68160200151826040015161208e565b6116025760405162461bcd60e51b815260040161050f90612d91565b6060806110006001600160a01b0316633b071dcc6040518163ffffffff1660e01b815260040160006040518083038186803b15801561164057600080fd5b505afa158015611654573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261167c91908101906127cb565b9150915060005b81518110156117b9576116ad82828151811061169b57fe5b60200260200101518560400151612266565b156117b1576006546040516309a99b4f60e41b815260646110028031909302049190639a99b4f0906116e59033908590600401612b48565b602060405180830381600087803b1580156116ff57600080fd5b505af1158015611713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117379190612a35565b506110006001600160a01b03166335409f7f85848151811061175557fe5b60200260200101516040518263ffffffff1660e01b81526004016117799190612b34565b600060405180830381600087803b15801561179357600080fd5b505af11580156117a7573d6000803e3d6000fd5b50505050506117b9565b600101611683565b506040808401519051630e9fbf5160e01b815261200291630e9fbf51916117e39190600401612b6c565b600060405180830381600087803b1580156117fd57600080fd5b505af1158015611811573d6000803e3d6000fd5b50505050505050565b61100381565b601481565b61200481565b60005460ff161561184e5760405162461bcd60e51b815260040161050f906130c0565b6032600455609660055560078054600160ff199182168117909255600080549091169091179055565b61100081565b336110001461189e5760405162461bcd60e51b815260040161050f90612ead565b60005460ff166118c05760405162461bcd60e51b815260040161050f90612c58565b6001546118cc57611cc4565b600154600090600019015b808211611c98576000805b828410156119fb576118f2612585565b600260006001878154811061190357fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff1615159082015260055490915060049004816020015111156119e55760046005548161197057fe5b0481602001510381602001818152505080600260006001888154811061199257fe5b6000918252602080832091909101546001600160a01b0316835282810193909352604091820190208351815591830151600183015591909101516002909101805460ff19169115159190911790556119ef565b60019250506119fb565b508360010193506118e2565b828411611b9257611a0a612585565b6002600060018681548110611a1b57fe5b60009182526020808320909101546001600160a01b0316835282810193909352604091820190208151606081018352815481526001820154938101939093526002015460ff161515908201526005549091506004900481602001511115611b0357600460055481611a8857fe5b04816020015103816020018181525050806002600060018781548110611aaa57fe5b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902083518155918301516001808401919091559201516002909101805460ff19169115159190911790559150611b929050565b6002600060018681548110611b1457fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff19169055805480611b5857fe5b600082815260209020810160001990810180546001600160a01b031916905501905583611b855750611b92565b50600019909201916119fb565b818015611b9c5750805b15611c7b576002600060018681548110611bb257fe5b60009182526020808320909101546001600160a01b031683528201929092526040018120818155600181810192909255600201805460ff19169055805484908110611bf957fe5b600091825260209091200154600180546001600160a01b039092169186908110611c1f57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506001805480611c5857fe5b600082815260209020810160001990810180546001600160a01b03191690550190555b82611c87575050611c98565b5050600190910190600019016118d7565b6040517fcfdb3b6ccaeccbdc68be3c59c840e3b3c90f0a7c491f5fff1cf56cfda200dd9c90600090a150505b565b61100481565b6060611cdf611cda836122ca565b611ce7565b90505b919050565b606081516001148015611d195750607f60f81b82600081518110611d0757fe5b01602001516001600160f81b03191611155b15611d25575080611ce2565b611cdf611d378351608060ff166123b0565b83612482565b6060815160001415611d5e5750604080516000815260208101909152611ce2565b606082600081518110611d6d57fe5b602002602001015190506000600190505b8351811015611dae57611da482858381518110611d9757fe5b6020026020010151612482565b9150600101611d7e565b50611dc7611dc1825160c060ff166123b0565b82612482565b9392505050565b8015611e30576040516375cc7d8960e01b8152612002906375cc7d8990611df9908690600401612b34565b600060405180830381600087803b158015611e1357600080fd5b505af1158015611e27573d6000803e3d6000fd5b50505050610905565b6040516375cc7d8960e01b8152612002906375cc7d8990611e55908690600401612b34565b600060405180830381600087803b158015611e6f57600080fd5b505af1925050508015611e80575060015b610905576040516000815260443d1015611e9c57506000611f39565b60046000803e60005160e01c6308c379a08114611ebd576000915050611f39565b60043d036004833e81513d602482011167ffffffffffffffff82111715611ee957600092505050611f39565b808301805167ffffffffffffffff811115611f0b576000945050505050611f39565b8060208301013d8601811115611f2957600095505050505050611f39565b601f01601f191660405250925050505b80611f445750611f8d565b836001600160a01b03167fd7bc86ff5d08c8ab043edec743302aba2520e6635172a428bc956721db9e2d1c8483604051611f7f9291906132a0565b60405180910390a250612002565b3d808015611fb7576040519150601f19603f3d011682016040523d82523d6000602084013e611fbc565b606091505b50836001600160a01b03167fd7bc86ff5d08c8ab043edec743302aba2520e6635172a428bc956721db9e2d1c8483604051611ff89291906132a0565b60405180910390a2505b610905565b60008160405160200161201a9190612b18565b60405160208183030381529060405280519060200120836040516020016120419190612b18565b604051602081830303815290604052805190602001201490505b92915050565b015190565b8082015160009060ff811615612080576001915081612086565b60009150815b505092915050565b60408051600480825260a0820190925260009160609190816020015b60608152602001906001900390816120aa5750506040805160208082528183019092529192506060919080820181803683370190505090506120ef8560000151611ccc565b826000815181106120fc57fe5b602002602001018190525061211760208660200151836124ff565b61212081611ce7565b8260018151811061212d57fe5b60200260200101819052506121458560400151611ccc565b8260028151811061215257fe5b602002602001018190525061216d60208660600151836124ff565b61217681611ce7565b8260038151811061218357fe5b60200260200101819052506121a9602061219c84611d3d565b80519060200120836124ff565b6040805160b080825260e082019092526060916020820181803683370190505090506121d981836000602061250f565b6121eb8187608001516020606061250f565b6121f981866080603061250f565b604080516001808252818301909252606091602082018180368337019050509050815160016020830182602086016066600019fa61223657600080fd5b506001612244826000612569565b60ff161461225957600094505050505061205b565b5060019695505050505050565b81518151600091600191811480831461228257600092506122c0565b600160208701838101602088015b6002848385100114156122bb5780518351146122af5760009650600093505b60209283019201612290565b505050505b5090949350505050565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff19841661230e57506018612332565b6fffffffffffffffffffffffffffffffff19841661232e57506010612332565b5060005b60208110156123685781818151811061234757fe5b01602001516001600160f81b0319161561236057612368565b600101612332565b60008160200390506060816040519080825280601f01601f19166020018201604052801561239d576020820181803683370190505b5080830196909652508452509192915050565b60606801000000000000000083106123da5760405162461bcd60e51b815260040161050f90612dc8565b604080516001808252818301909252606091602082018180368337019050509050603784116124345782840160f81b8160008151811061241657fe5b60200101906001600160f81b031916908160001a905350905061205b565b606061243f856122ca565b90508381510160370160f81b8260008151811061245857fe5b60200101906001600160f81b031916908160001a9053506124798282612482565b95945050505050565b6060806040519050835180825260208201818101602087015b818310156124b357805183526020928301920161249b565b50855184518101855292509050808201602086015b818310156124e05780518352602092830192016124c8565b508651929092011591909101601f01601f191660405250905092915050565b9091018181526020918201910152565b60005b818110156125625783818151811061252657fe5b602001015160f81c60f81b85848060010195508151811061254357fe5b60200101906001600160f81b031916908160001a905350600101612512565b5050505050565b6000816001018351101561257c57600080fd5b50016001015190565b604051806060016040528060008152602001600081526020016000151581525090565b600082601f8301126125b8578081fd5b81516125cb6125c68261331f565b6132f8565b818152915060208083019084810160005b84811015612641578151870188603f8201126125f757600080fd5b838101516126076125c68261333f565b81815260408b8184860101111561261d57600080fd5b61262c83888401838701613363565b508652505092820192908201906001016125dc565b505050505092915050565b60008083601f84011261265d578182fd5b50813567ffffffffffffffff811115612674578182fd5b60208301915083602082850101111561268c57600080fd5b9250929050565b600082601f8301126126a3578081fd5b81356126b16125c68261333f565b91508082528360208285010111156126c857600080fd5b8060208401602084013760009082016020015292915050565b600060a082840312156126f2578081fd5b6126fc60a06132f8565b905081358152602082013560208201526040820135604082015260608201356060820152608082013567ffffffffffffffff81111561273a57600080fd5b61274684828501612693565b60808301525092915050565b600060208284031215612763578081fd5b8135611dc781613393565b60006020828403121561277f578081fd5b8151611dc781613393565b60008060006060848603121561279e578182fd5b83356127a981613393565b92506020840135915060408401356127c0816133ab565b809150509250925092565b600080604083850312156127dd578182fd5b825167ffffffffffffffff808211156127f4578384fd5b81850186601f820112612805578485fd5b805192506128156125c68461331f565b80848252602080830192508084018a828389028701011115612835578889fd5b8894505b8685101561286057805161284c81613393565b845260019490940193928101928101612839565b508801519096509350505080821115612877578283fd5b50612884858286016125a8565b9150509250929050565b60006020828403121561289f578081fd5b8151611dc7816133ab565b600080604083850312156128bc578182fd5b823567ffffffffffffffff808211156128d3578384fd5b6128df86838701612693565b935060208501359150808211156128f4578283fd5b5061288485828601612693565b60008060008060408587031215612916578182fd5b843567ffffffffffffffff8082111561292d578384fd5b6129398883890161264c565b90965094506020870135915080821115612951578384fd5b5061295e8782880161264c565b95989497509550505050565b60006020828403121561297b578081fd5b813567ffffffffffffffff80821115612992578283fd5b818401606081870312156129a4578384fd5b6129ae60606132f8565b92508035828111156129be578485fd5b6129ca878284016126e1565b8452506020810135828111156129de578485fd5b6129ea878284016126e1565b602085015250604081013582811115612a01578485fd5b612a0d87828401612693565b6040850152509195945050505050565b600060208284031215612a2e578081fd5b5035919050565b600060208284031215612a46578081fd5b5051919050565b600080600060408486031215612a61578081fd5b833560ff81168114612a71578182fd5b9250602084013567ffffffffffffffff811115612a8c578182fd5b612a988682870161264c565b9497909650939450505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60008151808452612ae7816020860160208601613363565b601f01601f19169290920160200192915050565b600a81526919195c1c9958d85d195960b21b602082015260400190565b60008251612b2a818460208701613363565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b600060208252611dc76020830184612acf565b600082825260406020830152611dc760408301612afb565b600060408252612bab604083018688612aa5565b8281036020840152612bbe818587612aa5565b979650505050505050565b60208082526010908201526f195d9a59195b98d9481d1bdbc81bdb1960821b604082015260600190565b6020808252818101527f6d616c6963696f757320766f746520736c617368206e6f7420656e61626c6564604082015260600190565b6020808252601690820152751d985b1a59185d1bdc881b9bdd081b5a59dc985d195960521b604082015260600190565b60208082526019908201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604082015260600190565b6020808252602b908201527f746865206d616c6963696f757320766f746520736c6173682073636f7065206f60408201526a7574206f662072616e676560a81b606082015260800190565b6020808252601a908201527f6e6f2076696f6c6174696f6e206f6620766f74652072756c6573000000000000604082015260600190565b6020808252818101527f7468652066656c6f6e795468726573686f6c64206f7574206f662072616e6765604082015260600190565b6020808252602b908201527f6c656e677468206f6620656e61626c654d616c6963696f7573566f7465536c6160408201526a0e6d040dad2e6dac2e8c6d60ab1b606082015260800190565b60208082526017908201527f766572696679207369676e6174757265206661696c6564000000000000000000604082015260600190565b6020808252600e908201526d696e70757420746f6f206c6f6e6760901b604082015260600190565b60208082526019908201527f7372634e756d20626967676572207468616e207461724e756d00000000000000604082015260600190565b600060208252611cdf60208301612afb565b60208082526027908201527f6c656e677468206f66206d697364656d65616e6f725468726573686f6c64206d6040820152660d2e6dac2e8c6d60cb1b606082015260800190565b60208082526013908201527274776f206964656e746963616c20766f74657360681b604082015260600190565b60208082526030908201527f746865206d6573736167652073656e646572206d7573742062652076616c696460408201526f185d1bdc94d95d0818dbdb9d1c9858dd60821b606082015260800190565b60208082526023908201527f6c656e677468206f662066656c6f6e79536c61736853636f7065206d69736d616040820152620e8c6d60eb1b606082015260800190565b6020808252601490820152736761737072696365206973206e6f74207a65726f60601b604082015260600190565b60208082526029908201527f6c656e677468206f662066656c6f6e79536c617368526577617264526174696f604082015268040dad2e6dac2e8c6d60bb1b606082015260800190565b6020808252601590820152741d9bdd195059191c881a5cc81b9bdd08199bdd5b99605a1b604082015260600190565b6020808252602e908201527f746865206d6573736167652073656e646572206d75737420626520676f76657260408201526d1b985b98d94818dbdb9d1c9858dd60921b606082015260800190565b60208082526022908201527f6c656e677468206f662066656c6f6e795468726573686f6c64206d69736d61746040820152610c6d60f31b606082015260800190565b6020808252602a908201527f7468652066656c6f6e7920736c6173682072657761726420726174696f206f7560408201526974206f662072616e676560b01b606082015260800190565b60208082526019908201527f74686520636f6e747261637420616c726561647920696e697400000000000000604082015260600190565b6020808252600c908201526b32b6b83a3c903432b0b232b960a11b604082015260600190565b60208082526025908201527f746865206d697364656d65616e6f725468726573686f6c64206f7574206f662060408201526472616e676560d81b606082015260800190565b6020808252602f908201527f746865206d6573736167652073656e646572206d7573742062652063726f737360408201526e0818da185a5b8818dbdb9d1c9858dd608a1b606082015260800190565b6020808252602d908201527f746865206d6573736167652073656e646572206d75737420626520746865206260408201526c3637b1b590383937b23ab1b2b960991b606082015260800190565b6020808252600d908201526c756e6b6e6f776e20706172616d60981b604082015260600190565b6020808252601490820152731d185c99d95d08189b1bd8dac81d1bdbc81bdb1960621b604082015260600190565b6020808252818101527f63616e206e6f7420736c61736820747769636520696e206f6e6520626c6f636b604082015260600190565b61ffff91909116815260200190565b90815260200190565b6000838252604060208301526132b96040830184612acf565b949350505050565b918252602082015260400190565b92835260208301919091521515604082015260600190565b63ffffffff91909116815260200190565b60405181810167ffffffffffffffff8111828210171561331757600080fd5b604052919050565b600067ffffffffffffffff821115613335578081fd5b5060209081020190565b600067ffffffffffffffff821115613355578081fd5b50601f01601f191660200190565b60005b8381101561337e578181015183820152602001613366565b8381111561338d576000848401525b50505050565b6001600160a01b03811681146133a857600080fd5b50565b80151581146133a857600080fdfea164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001002": { + "balance": "0x0", + "code": "0x60806040526004361061016a5760003560e01c80639dc09262116100d1578063ac4317511161008a578063df8079e911610064578063df8079e9146104da578063f9a2bbc7146104ef578063fb5478b314610504578063fd6a687914610519576101ae565b8063ac431751146103e1578063c81b1662146104b0578063dc927faf146104c5576101ae565b80639dc092621461034a578063a1a11bf51461035f578063a78abc1614610374578063aa82dce114610389578063aad560631461039e578063ab51bb96146103b3576101ae565b806351e806721161012357806351e80672146102765780636d70f7ae1461028b5780636e47b482146102d257806375d47a0a146102e75780637e434d54146102fc5780639a99b4f014610311576101ae565b80630e2374a5146101b357806328087028146101e45780633a0b0eff146101f957806343756e5c14610220578063493279b11461023557806351b4dce314610261576101ae565b366101ae5734156101ac5760408051348152905133917f6c98249d85d88c3753a04a22230f595e4dc8d3dc86c34af35deeeedc861b89db919081900360200190a25b005b600080fd5b3480156101bf57600080fd5b506101c861052e565b604080516001600160a01b039092168252519081900360200190f35b3480156101f057600080fd5b506101c8610534565b34801561020557600080fd5b5061020e61053a565b60408051918252519081900360200190f35b34801561022c57600080fd5b506101c8610540565b34801561024157600080fd5b5061024a610546565b6040805161ffff9092168252519081900360200190f35b34801561026d57600080fd5b506101c861054c565b34801561028257600080fd5b506101c8610552565b34801561029757600080fd5b506102be600480360360208110156102ae57600080fd5b50356001600160a01b0316610558565b604080519115158252519081900360200190f35b3480156102de57600080fd5b506101c8610576565b3480156102f357600080fd5b506101c861057c565b34801561030857600080fd5b506101c8610582565b34801561031d57600080fd5b5061020e6004803603604081101561033457600080fd5b506001600160a01b038135169060200135610588565b34801561035657600080fd5b506101c8610788565b34801561036b57600080fd5b506101c861078e565b34801561038057600080fd5b506102be610794565b34801561039557600080fd5b506101c861079d565b3480156103aa57600080fd5b506101c86107a3565b3480156103bf57600080fd5b506103c86107a9565b6040805163ffffffff9092168252519081900360200190f35b3480156103ed57600080fd5b506101ac6004803603604081101561040457600080fd5b81019060208101813564010000000081111561041f57600080fd5b82018360208201111561043157600080fd5b8035906020019184600183028401116401000000008311171561045357600080fd5b91939092909160208101903564010000000081111561047157600080fd5b82018360208201111561048357600080fd5b803590602001918460018302840111640100000000831117156104a557600080fd5b5090925090506107ae565b3480156104bc57600080fd5b506101c8610b31565b3480156104d157600080fd5b506101c8610b37565b3480156104e657600080fd5b506101c8610b3d565b3480156104fb57600080fd5b506101c8610b43565b34801561051057600080fd5b5061020e610b49565b34801561052557600080fd5b506101c8610b55565b61200181565b61200581565b60015481565b61100181565b6102ca81565b61200681565b61200081565b6001600160a01b031660009081526002602052604090205460ff1690565b61100581565b61100881565b61200381565b6000805460ff1661065a5760026020527fe57bda0a954a7c7381b17b2c763e646ba2c60f67292d287ba583603e2c1c41668054600160ff1991821681179092557fe25235fc0de9d7165652bef0846fefda506174abb9a190f03d0f7bcc6146dbce80548216831790557ffcc09d5775472c6fa988b216f5ce189894c14e093527f732b9b65da0880b5f81805482168317905561100160009081527fd5856b6520af3fbaacead8d875ff5c4db19c2ad37c909e14d0ea394740e2ebc8805483168417905560048355805490911690911790555b3360009081526002602052604090205460ff166106a85760405162461bcd60e51b815260040180806020018281038252602b815260200180610c43602b913960400191505060405180910390fd5b60004783106106b757476106b9565b825b9050674563918244f400008111156106d65750674563918244f400005b8015610757576040516001600160a01b0385169082156108fc029083906000818181858888f19350505050158015610712573d6000803e3d6000fd5b506040805182815290516001600160a01b038616917ff8b71c64315fc33b2ead2adfa487955065152a8ac33d9d5193aafd7f45dc15a0919081900360200190a2610781565b6040517fe589651933c2457488cc0d8e0941518abf748e799435e4e396d9c4d0b2db2d4d90600090a15b9392505050565b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b33611007146107ee5760405162461bcd60e51b815260040180806020018281038252602e815260200180610c9d602e913960400191505060405180910390fd5b61085084848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600b81526a30b23227b832b930ba37b960a91b60208201529150610b5b9050565b1561092857606082828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050825192935050601490911490506108d35760405162461bcd60e51b815260040180806020018281038252602c815260200180610ccb602c913960400191505060405180910390fd5b60148101516001600160a01b038116600081815260026020526040808220805460ff19166001179055517f9870d7fe5d112134c55844951dedf365363006d9c588db07c4c85af6322a06199190a25050610a9f565b61098d84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600e81526d3232b632ba32a7b832b930ba37b960911b60208201529150610b5b9050565b15610a6257606082828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505060149091149050610a105760405162461bcd60e51b815260040180806020018281038252602f815260200180610c6e602f913960400191505060405180910390fd5b60148101516001600160a01b038116600081815260026020526040808220805460ff19169055517fb40992a19dba61ea600e87fce607102bf5908dc89076217b6ca6ae195224f7029190a25050610a9f565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b61100281565b61100381565b61200481565b61100081565b674563918244f4000081565b61100481565b6000816040516020018082805190602001908083835b60208310610b905780518252601f199092019160209182019101610b71565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b60208310610bfe5780518252601f199092019160209182019101610bdf565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052805190602001201490509291505056fe6f6e6c79206f70657261746f7220697320616c6c6f77656420746f2063616c6c20746865206d6574686f646c656e677468206f662076616c756520666f722064656c6574654f70657261746f722073686f756c64206265203230746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163746c656e677468206f662076616c756520666f72206164644f70657261746f722073686f756c64206265203230a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001003": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106102115760003560e01c8063aad5606311610125578063dda83148116100ad578063e2761af01161007c578063e2761af01461064f578063e405bbc314610673578063ea54b2aa1461067b578063f9a2bbc714610683578063fd6a68791461068b57610211565b8063dda83148146105f3578063df5fe70414610619578063df8079e91461063f578063e1c7392a1461064757610211565b8063c81b1662116100f4578063c81b16621461051e578063cba510a914610526578063d81698791461054c578063da8d08f0146105c5578063dc927faf146105eb57610211565b8063aad5606314610429578063ab51bb9614610431578063ac43175114610452578063adc879e91461051657610211565b8063564b81ef116101a85780637e434d54116101775780637e434d54146103ed5780639dc09262146103f5578063a1a11bf5146103fd578063a78abc1614610405578063aa82dce11461042157610211565b8063564b81ef1461029b5780635c5ae8db146103185780636e47b482146103dd57806375d47a0a146103e557610211565b806343756e5c116101e457806343756e5c14610264578063493279b11461026c57806351b4dce31461028b57806351e806721461029357610211565b80630e2374a5146102165780632657e9b61461023a578063280870281461025457806333f7798d1461025c575b600080fd5b61021e610693565b604080516001600160a01b039092168252519081900360200190f35b610242610699565b60408051918252519081900360200190f35b61021e6106a4565b6102426106aa565b61021e6106b0565b6102746106b6565b6040805161ffff9092168252519081900360200190f35b61021e6106bc565b61021e6106c2565b6102a36106c8565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102dd5781810151838201526020016102c5565b50505050905090810190601f16801561030a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61033e6004803603602081101561032e57600080fd5b50356001600160401b03166107d3565b60405180856001600160401b03166001600160401b0316815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561039f578181015183820152602001610387565b50505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390f35b61021e61088e565b61021e610894565b61021e61089a565b61021e6108a0565b61021e6108a6565b61040d6108ac565b604080519115158252519081900360200190f35b61021e6108b5565b61021e6108bb565b6104396108c1565b6040805163ffffffff9092168252519081900360200190f35b6105146004803603604081101561046857600080fd5b81019060208101813564010000000081111561048357600080fd5b82018360208201111561049557600080fd5b803590602001918460018302840111640100000000831117156104b757600080fd5b9193909290916020810190356401000000008111156104d557600080fd5b8201836020820111156104e757600080fd5b8035906020019184600183028401116401000000008311171561050957600080fd5b5090925090506108c6565b005b610242610997565b61021e61099d565b6102426004803603602081101561053c57600080fd5b50356001600160401b03166109a3565b61040d6004803603604081101561056257600080fd5b81019060208101813564010000000081111561057d57600080fd5b82018360208201111561058f57600080fd5b803590602001918460018302840111640100000000831117156105b157600080fd5b9193509150356001600160401b03166109c2565b61021e600480360360208110156105db57600080fd5b50356001600160401b0316610a82565b61021e610a9d565b61021e6004803603602081101561060957600080fd5b50356001600160401b0316610aa3565b61040d6004803603602081101561062f57600080fd5b50356001600160401b0316610ac7565b61021e610b09565b610514610b0f565b610657610baf565b604080516001600160401b039092168252519081900360200190f35b610657610bbe565b6102a3610bd9565b61021e610bf8565b61021e610bfe565b61200181565b662386f26fc1000081565b61200581565b60055481565b61100181565b6102ca81565b61200681565b61200081565b604080516020808252818301909252606091829190602082018180368337505060045460208301525090506000805b60208160ff16101561073e57828160ff168151811061071257fe5b01602001516001600160f81b0319161561073157816001019150610736565b61073e565b6001016106f7565b5060608160ff166040519080825280601f01601f19166020018201604052801561076f576020820181803683370190505b50905060005b8260ff168160ff1610156107cb57838160ff168151811061079257fe5b602001015160f81c60f81b828260ff16815181106107ac57fe5b60200101906001600160f81b031916908160001a905350600101610775565b509250505090565b60016020818152600092835260409283902080548184015460028084015460038501805489516101009982161599909902600019011692909204601f81018790048702880187019098528787526001600160401b0390931696919592949091908301828280156108845780601f1061085957610100808354040283529160200191610884565b820191906000526020600020905b81548152906001019060200180831161086757829003601f168201915b5050505050905084565b61100581565b61100881565b61200381565b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b60005460ff1661091d576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604482015290519081900360640190fd5b336110071461095d5760405162461bcd60e51b815260040180806020018281038252602e815260200180610c0f602e913960400191505060405180910390fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b60045481565b61100281565b6001600160401b03166000908152600160208190526040909120015490565b60408051630a83aaa960e31b815233600482015290516000916110069163541d554891602480820192602092909190829003018186803b158015610a0557600080fd5b505afa158015610a19573d6000803e3d6000fd5b505050506040513d6020811015610a2f57600080fd5b505161095d576040805162461bcd60e51b815260206004820152601f60248201527f746865206d73672073656e646572206973206e6f7420612072656c6179657200604482015290519081900360640190fd5b6002602052600090815260409020546001600160a01b031681565b61100381565b6001600160401b03166000908152600260205260409020546001600160a01b031690565b6001600160401b0381166000908152600260205260408120546001600160a01b0316151580610b0357506003546001600160401b038381169116145b92915050565b61200481565b60005460ff1615610b67576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b600080610b8e6040518061024001604052806102208152602001610c3d6102209139610c04565b505160045550506000805460ff19166001179055662386f26fc10000600555565b6003546001600160401b031681565b6003546801000000000000000090046001600160401b031681565b6040518061024001604052806102208152602001610c3d610220913981565b61100081565b61100481565b805160209091019156fe746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e747261637442696e616e63652d436861696e2d5469677269730000000000000000000000000000000006915167cedaf7bbf7df47d932fdda630527ee648562cf3e52c5e5f46156a3a971a4ceb443c53a50d8653ef8cf1e5716da68120fb51b636dc6d111ec3277b098ecd42d49d3769d8a1f78b4c17a965f7a30d4181fabbd1f969f46d3c8e83b5ad4845421d8000000e8d4a510002ba4e81542f437b7ae1f8a35ddb233c789a8dc22734377d9b6d63af1ca403b61000000e8d4a51000df8da8c5abfdb38595391308bb71e5a1e0aabdc1d0cf38315d50d6be939b2606000000e8d4a51000b6619edca4143484800281d698b70c935e9152ad57b31d85c05f2f79f64b39f3000000e8d4a510009446d14ad86c8d2d74780b0847110001a1c2e252eedfea4753ebbbfce3a22f52000000e8d4a510000353c639f80cc8015944436dab1032245d44f912edc31ef668ff9f4a45cd0599000000e8d4a51000e81d3797e0544c3a718e1f05f0fb782212e248e784c1a851be87e77ae0db230e000000e8d4a510005e3fcda30bd19d45c4b73688da35e7da1fce7c6859b2c1f20ed5202d24144e3e000000e8d4a51000b06a59a2d75bf5d014fce7c999b5e71e7a960870f725847d4ba3235baeaa08ef000000e8d4a510000c910e2fe650e4e01406b3310b489fb60a84bc3ff5c5bee3a56d5898b6a8af32000000e8d4a5100071f2d7b8ec1c8b99a653429b0118cd201f794f409d0fea4d65b1b662f2b00063000000e8d4a51000a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001004": { + "balance": "176405560900000000000000000", + "code": "0x60806040526004361061036f5760003560e01c80639509b980116101c6578063bbface1f116100f7578063e04c83a711610095578063f9a2bbc71161006f578063f9a2bbc714610e57578063fa9e915914610e6c578063fc1a598f14610e81578063fd6a687914610eb4576103b7565b8063e04c83a714610de5578063e1c7392a14610e0f578063e8f35cea14610e24576103b7565b8063c8509d81116100d1578063c8509d8114610960578063cf41984414610d80578063dc927faf14610dbb578063df8079e914610dd0576103b7565b8063bbface1f14610d05578063bd46646114610d38578063c81b166214610d6b576103b7565b8063aa82dce111610164578063ac4317511161013e578063ac43175114610bd7578063b99328c514610ca2578063b9fd21e314610cdb578063ba35ead614610cf0576103b7565b8063aa82dce114610b7f578063aad5606314610b94578063ab51bb9614610ba9576103b7565b80639dc09262116101a05780639dc0926214610af9578063a1a11bf514610b0e578063a78abc1614610b23578063aa7415f514610b38576103b7565b80639509b98014610a725780639a854bbd14610aab5780639a99b4f014610ac0576103b7565b806359b92789116102a057806375d47a0a1161023e578063831d65d111610218578063831d65d1146109605780638525db03146109e55780638eff336c14610a1e57806393ab703f14610a5d576103b7565b806375d47a0a146108f7578063799758b91461090c5780637e434d541461094b576103b7565b80636e0565201161027a5780636e056520146107775780636e47b482146108a357806371d30863146108b8578063727be1f8146108cd576103b7565b806359b927891461070d5780635d499b1b14610737578063613684751461074c576103b7565b80633fd8b02f1161030d578063493279b1116102e7578063493279b1146106a257806350432d32146106ce57806351b4dce3146106e357806351e80672146106f8576103b7565b80633fd8b02f1461066357806343756e5c1461067857806343a368b91461068d576103b7565b8063149d14d911610349578063149d14d91461052257806328087028146105495780632ae454831461055e5780633d713223146105b2576103b7565b80630e2374a5146103bc5780631182b875146103ed57806312234582146104e7576103b7565b366103b75734156103b5576040805133815234602082015281517f6c98249d85d88c3753a04a22230f595e4dc8d3dc86c34af35deeeedc861b89db929181900390910190a15b005b600080fd5b3480156103c857600080fd5b506103d1610ec9565b604080516001600160a01b039092168252519081900360200190f35b3480156103f957600080fd5b506104726004803603604081101561041057600080fd5b60ff8235169190810190604081016020820135600160201b81111561043457600080fd5b82018360208201111561044657600080fd5b803590602001918460018302840111600160201b8311171561046757600080fd5b509092509050610ecf565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104ac578181015183820152602001610494565b50505050905090810190601f1680156104d95780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104f357600080fd5b506103b56004803603604081101561050a57600080fd5b506001600160a01b0381358116916020013516610f17565b34801561052e57600080fd5b50610537610f91565b60408051918252519081900360200190f35b34801561055557600080fd5b506103d1610f97565b34801561056a57600080fd5b506105996004803603604081101561058157600080fd5b506001600160a01b0381358116916020013516610f9d565b6040805192835260208301919091528051918290030190f35b3480156105be57600080fd5b506103d1600480360360208110156105d557600080fd5b810190602081018135600160201b8111156105ef57600080fd5b82018360208201111561060157600080fd5b803590602001918460018302840111600160201b8311171561062257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610fc1945050505050565b34801561066f57600080fd5b50610537610fe2565b34801561068457600080fd5b506103d1610fe8565b34801561069957600080fd5b50610537610fee565b3480156106ae57600080fd5b506106b7610ffa565b6040805161ffff9092168252519081900360200190f35b3480156106da57600080fd5b50610537611000565b3480156106ef57600080fd5b506103d161100b565b34801561070457600080fd5b506103d1611011565b34801561071957600080fd5b506103d16004803603602081101561073057600080fd5b5035611017565b34801561074357600080fd5b50610537611032565b34801561075857600080fd5b5061076161103b565b6040805160ff9092168252519081900360200190f35b61088f6004803603608081101561078d57600080fd5b810190602081018135600160201b8111156107a757600080fd5b8201836020820111156107b957600080fd5b803590602001918460208302840111600160201b831117156107da57600080fd5b919390929091602081019035600160201b8111156107f757600080fd5b82018360208201111561080957600080fd5b803590602001918460208302840111600160201b8311171561082a57600080fd5b919390929091602081019035600160201b81111561084757600080fd5b82018360208201111561085957600080fd5b803590602001918460208302840111600160201b8311171561087a57600080fd5b91935091503567ffffffffffffffff16611040565b604080519115158252519081900360200190f35b3480156108af57600080fd5b506103d1611086565b3480156108c457600080fd5b5061053761108c565b3480156108d957600080fd5b5061088f600480360360208110156108f057600080fd5b5035611092565b34801561090357600080fd5b506103d16110ce565b34801561091857600080fd5b506103b56004803603606081101561092f57600080fd5b508035906001600160a01b0360208201351690604001356110d4565b34801561095757600080fd5b506103d1611384565b34801561096c57600080fd5b506103b56004803603604081101561098357600080fd5b60ff8235169190810190604081016020820135600160201b8111156109a757600080fd5b8201836020820111156109b957600080fd5b803590602001918460018302840111600160201b831117156109da57600080fd5b50909250905061138a565b3480156109f157600080fd5b506103b560048036036040811015610a0857600080fd5b50803590602001356001600160a01b03166113cf565b348015610a2a57600080fd5b506103b560048036036060811015610a4157600080fd5b508035906001600160a01b036020820135169060400135611538565b348015610a6957600080fd5b50610537611578565b348015610a7e57600080fd5b506103b560048036036040811015610a9557600080fd5b506001600160a01b03813516906020013561157f565b348015610ab757600080fd5b50610537611641565b348015610acc57600080fd5b5061053760048036036040811015610ae357600080fd5b506001600160a01b03813516906020013561164d565b348015610b0557600080fd5b506103d16116d3565b348015610b1a57600080fd5b506103d16116d9565b348015610b2f57600080fd5b5061088f6116df565b61088f60048036036080811015610b4e57600080fd5b5080356001600160a01b03908116916020810135909116906040810135906060013567ffffffffffffffff16611040565b348015610b8b57600080fd5b506103d16116e8565b348015610ba057600080fd5b506103d16116ee565b348015610bb557600080fd5b50610bbe6116f4565b6040805163ffffffff9092168252519081900360200190f35b348015610be357600080fd5b506103b560048036036040811015610bfa57600080fd5b810190602081018135600160201b811115610c1457600080fd5b820183602082011115610c2657600080fd5b803590602001918460018302840111600160201b83111715610c4757600080fd5b919390929091602081019035600160201b811115610c6457600080fd5b820183602082011115610c7657600080fd5b803590602001918460018302840111600160201b83111715610c9757600080fd5b5090925090506116f9565b348015610cae57600080fd5b506103b560048036036040811015610cc557600080fd5b50803590602001356001600160a01b0316611538565b348015610ce757600080fd5b50610537611739565b348015610cfc57600080fd5b50610537611743565b348015610d1157600080fd5b5061053760048036036020811015610d2857600080fd5b50356001600160a01b0316611749565b348015610d4457600080fd5b5061053760048036036020811015610d5b57600080fd5b50356001600160a01b031661175b565b348015610d7757600080fd5b506103d1611776565b348015610d8c57600080fd5b506103b560048036036040811015610da357600080fd5b506001600160a01b038135811691602001351661177c565b348015610dc757600080fd5b506103d1611a50565b348015610ddc57600080fd5b506103d1611a56565b348015610df157600080fd5b5061088f60048036036020811015610e0857600080fd5b5035611a5c565b348015610e1b57600080fd5b506103b5611ab4565b348015610e3057600080fd5b5061053760048036036020811015610e4757600080fd5b50356001600160a01b0316611b54565b348015610e6357600080fd5b506103d1611b66565b348015610e7857600080fd5b50610537611b6c565b348015610e8d57600080fd5b5061047260048036036020811015610ea457600080fd5b50356001600160a01b0316611b72565b348015610ec057600080fd5b506103d1611c99565b61200181565b60005460609060ff16610f17576040805162461bcd60e51b8152602060048201526019602482015260008051602061204a833981519152604482015290519081900360640190fd5b3361200014610f575760405162461bcd60e51b815260040180806020018281038252602f815260200180611ff8602f913960400191505060405180910390fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b60015490565b61200581565b60076020908152600092835260408084209091529082529020805460019091015482565b6020908101516000908152600490915260409020546001600160a01b031690565b60055481565b61100181565b670de0b6b3a764000081565b6102ca81565b66071afd498d000081565b61200681565b61200081565b6000908152600460205260409020546001600160a01b031690565b6402540be40081565b600881565b6000805460ff16610f57576040805162461bcd60e51b8152602060048201526019602482015260008051602061204a833981519152604482015290519081900360640190fd5b61100581565b60015481565b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152905160009181900360640190fd5b61100881565b60005460ff16611119576040805162461bcd60e51b8152602060048201526019602482015260008051602061204a833981519152604482015290519081900360640190fd5b33613000146111595760405162461bcd60e51b815260040180806020018281038252602b815260200180611f7e602b913960400191505060405180910390fd5b677ce66c50e28400008111156111a05760405162461bcd60e51b8152600401808060200182810382526035815260200180611f496035913960400191505060405180910390fd5b60006221272160e91b841461130a576000848152600460205260409020546001600160a01b031680611213576040805184815290516001600160a01b0386169187917fc16ee9013bf67c846d37735983debb0acc5b2d1419cb5931c9843ad4689505499181900360200190a3505061137f565b6001600160a01b0381166000908152600260205260409020546112368482611c9f565b604080516370a0823160e01b8152306004820152905191945084916001600160a01b038516916370a08231916024808301926020929190829003018186803b15801561128157600080fd5b505afa158015611295573d6000803e3d6000fd5b505050506040513d60208110156112ab57600080fd5b505110156112f7576040805162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b604482015290519081900360640190fd5b61130386838588611ce8565b505061137d565b61131f826402540be40063ffffffff611d8216565b90508047101561136d576040805162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b604482015290519081900360640190fd5b600061137b85828487611ce8565b505b505b505050565b61200381565b60005460ff16610f17576040805162461bcd60e51b8152602060048201526019602482015260008051602061204a833981519152604482015290519081900360640190fd5b336130001461140f5760405162461bcd60e51b815260040180806020018281038252602b815260200180611f7e602b913960400191505060405180910390fd5b60006221272160e91b831461147a57506000828152600460205260409020546001600160a01b03168061147a576040805162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081cde5b589bdb60921b604482015290519081900360640190fd5b6001600160a01b03808216600090815260076020908152604080832093861683529290522080546114e5576040805162461bcd60e51b815260206004820152601060248201526f1b9bc81b1bd8dad95908185b5bdd5b9d60821b604482015290519081900360640190fd5b8054600082556040805182815290516001600160a01b03808716929086169188917f8041a9a8704332594e2884f5e0f942281cdd7611854c365b4d0aa70b2295d6b6919081900360200190a45050505050565b3361100814610f575760405162461bcd60e51b81526004018080602001828103825260238152602001806120276023913960400191505060405180910390fd5b62093a8081565b81806001600160a01b031663893d20e86040518163ffffffff1660e01b815260040160206040518083038186803b1580156115b957600080fd5b505afa1580156115cd573d6000803e3d6000fd5b505050506040513d60208110156115e357600080fd5b50516001600160a01b03163314610f57576040805162461bcd60e51b815260206004820152601860248201527f6e6f74206f776e6572206f6620424550323020746f6b656e0000000000000000604482015290519081900360640190fd5b677ce66c50e284000081565b6000805460ff16611693576040805162461bcd60e51b8152602060048201526019602482015260008051602061204a833981519152604482015290519081900360640190fd5b3361100514610f575760405162461bcd60e51b815260040180806020018281038252602f815260200180611f1a602f913960400191505060405180910390fd5b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b3361100714610f575760405162461bcd60e51b815260040180806020018281038252602e815260200180611fca602e913960400191505060405180910390fd5b6221272160e91b81565b61c35081565b60026020526000908152604090205481565b6001600160a01b031660009081526003602052604090205490565b61100281565b60085460ff16600214156117c8576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b6008805460ff191660021790556001600160a01b0380831660009081526007602090815260408083209385168352929052208054611840576040805162461bcd60e51b815260206004820152601060248201526f1b9bc81b1bd8dad95908185b5bdd5b9d60821b604482015290519081900360640190fd5b8060010154421015611899576040805162461bcd60e51b815260206004820152601760248201527f7374696c6c206f6e206c6f636b696e6720706572696f64000000000000000000604482015290519081900360640190fd5b805460008083556001600160a01b03851661190c576040516001600160a01b038516906127109084906000818181858888f193505050503d80600081146118fc576040519150601f19603f3d011682016040523d82523d6000602084013e611901565b606091505b50508091505061199f565b846001600160a01b031663a9059cbb61c35086856040518463ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600088803b15801561196f57600080fd5b5087f1158015611983573d6000803e3d6000fd5b50505050506040513d602081101561199a57600080fd5b505190505b806119f1576040805162461bcd60e51b815260206004820152601e60248201527f776974686472617720756e6c6f636b656420746f6b656e206661696c65640000604482015290519081900360640190fd5b836001600160a01b0316856001600160a01b03167f832fc3e25f2b3e6fb0eb59419a73cba405f2a249fce75f7e31ea5a457a0323f1846040518082815260200191505060405180910390a350506008805460ff19166001179055505050565b61100381565b61200481565b60003361200214610f57576040805162461bcd60e51b815260206004820152601f60248201527f746865206d73672073656e646572206d757374206265207374616b6548756200604482015290519081900360640190fd5b60005460ff1615611b0c576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b66071afd498d000060019081556000808052600260205260127fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b55805460ff19169091179055565b60066020526000908152604090205481565b61100081565b61271081565b6001600160a01b03811660009081526003602090815260409182902054825182815280840190935260609290918391906020820181803683375050506020810183905290506000805b60208160ff161015611c0257828160ff1681518110611bd657fe5b01602001516001600160f81b03191615611bf557816001019150611bfa565b611c02565b600101611bbb565b5060608160ff166040519080825280601f01601f191660200182016040528015611c33576020820181803683370190505b50905060005b8260ff168160ff161015611c8f57838160ff1681518110611c5657fe5b602001015160f81c60f81b828260ff1681518110611c7057fe5b60200101906001600160f81b031916908160001a905350600101611c39565b5095945050505050565b61100481565b60006008821115611cc857611cc1836007198401600a0a63ffffffff611d8216565b9050611ce2565b611cdf836008849003600a0a63ffffffff611ddb16565b90505b92915050565b6001600160a01b0380841660009081526007602090815260408083209385168352929052208054611d1f908463ffffffff611e1d16565b81554262093a80016001820181905560408051858152602081019290925280516001600160a01b03808616939088169289927f446d1aa056e7b903901f49880e9f252762c1b81dc4301cf28db6dae526497eaa9281900390910190a45050505050565b600082611d9157506000611ce2565b82820282848281611d9e57fe5b0414611cdf5760405162461bcd60e51b8152600401808060200182810382526021815260200180611fa96021913960400191505060405180910390fd5b6000611cdf83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611e77565b600082820183811015611cdf576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008183611f035760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611ec8578181015183820152602001611eb0565b50505050905090810190601f168015611ef55780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581611f0f57fe5b049594505050505056fe746865206d6573736167652073656e646572206d75737420626520696e63656e746976697a6520636f6e7472616374616d6f756e7420697320746f6f206c617267652c20657863656564206d6178696d756d206265703220746f6b656e20616d6f756e74746865206d73672073656e646572206d75737420626520746f6b656e207265636f76657220706f7274616c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d73672073656e646572206d75737420626520746f6b656e4d616e6167657274686520636f6e7472616374206e6f7420696e69742079657400000000000000a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001005": { + "balance": "0x0", + "code": "0x60806040526004361061024a5760003560e01c8063930e1b0911610139578063ace9fcc2116100b6578063df8079e91161007a578063df8079e9146106d5578063e1c7392a146106ea578063e89a3020146106ff578063f9a2bbc714610729578063fd6a68791461073e578063fdd31fcd1461075357610251565b8063ace9fcc21461066c578063c81b166214610681578063d0ab528a14610696578063dc927faf146106ab578063dcae76ab146106c057610251565b8063a7c6a59d116100fd578063a7c6a59d1461052e578063aa82dce114610543578063aad5606314610558578063ab51bb961461056d578063ac4317511461059b57610251565b8063930e1b09146104a75780639dc09262146104da578063a1a11bf5146104ef578063a3c3c0ad14610504578063a78abc161461051957610251565b806343756e5c116101c75780636f93d2e61161018b5780636f93d2e6146103f457806374f2272d1461045357806375d47a0a146104685780637e146cc51461047d5780637e434d541461049257610251565b806343756e5c14610374578063493279b11461038957806351b4dce3146103b557806351e80672146103ca5780636e47b482146103df57610251565b80631b20087c1161020e5780631b20087c146102ed5780631c64331214610302578063280870281461032c5780633a9756121461025657806340bb43c01461034157610251565b8063081e9d1314610256578063093f2fc41461027d5780630e2374a51461029257806310e06a76146102c357806312950c46146102d857610251565b3661025157005b600080fd5b34801561026257600080fd5b5061026b610786565b60408051918252519081900360200190f35b34801561028957600080fd5b5061026b61078b565b34801561029e57600080fd5b506102a7610790565b604080516001600160a01b039092168252519081900360200190f35b3480156102cf57600080fd5b5061026b610796565b3480156102e457600080fd5b5061026b61079c565b3480156102f957600080fd5b5061026b6107a2565b34801561030e57600080fd5b506102a76004803603602081101561032557600080fd5b50356107a8565b34801561033857600080fd5b506102a76107cf565b34801561034d57600080fd5b5061026b6004803603602081101561036457600080fd5b50356001600160a01b03166107d5565b34801561038057600080fd5b506102a76107e7565b34801561039557600080fd5b5061039e6107ed565b6040805161ffff9092168252519081900360200190f35b3480156103c157600080fd5b506102a76107f3565b3480156103d657600080fd5b506102a76107f9565b3480156103eb57600080fd5b506102a76107ff565b34801561040057600080fd5b5061043f6004803603608081101561041757600080fd5b506001600160a01b038135811691602081013590911690604081013590606001351515610805565b604080519115158252519081900360200190f35b34801561045f57600080fd5b5061026b6108d7565b34801561047457600080fd5b506102a76108dd565b34801561048957600080fd5b5061026b6108e3565b34801561049e57600080fd5b506102a76108e8565b3480156104b357600080fd5b5061026b600480360360208110156104ca57600080fd5b50356001600160a01b03166108ee565b3480156104e657600080fd5b506102a7610900565b3480156104fb57600080fd5b506102a7610906565b34801561051057600080fd5b5061026b61090c565b34801561052557600080fd5b5061043f610912565b34801561053a57600080fd5b5061026b61091b565b34801561054f57600080fd5b506102a7610921565b34801561056457600080fd5b506102a7610927565b34801561057957600080fd5b5061058261092d565b6040805163ffffffff9092168252519081900360200190f35b3480156105a757600080fd5b5061066a600480360360408110156105be57600080fd5b8101906020810181356401000000008111156105d957600080fd5b8201836020820111156105eb57600080fd5b8035906020019184600183028401116401000000008311171561060d57600080fd5b91939092909160208101903564010000000081111561062b57600080fd5b82018360208201111561063d57600080fd5b8035906020019184600183028401116401000000008311171561065f57600080fd5b509092509050610932565b005b34801561067857600080fd5b5061026b610972565b34801561068d57600080fd5b506102a7610978565b3480156106a257600080fd5b5061026b61097e565b3480156106b757600080fd5b506102a7610984565b3480156106cc57600080fd5b5061026b61098a565b3480156106e157600080fd5b506102a7610990565b3480156106f657600080fd5b5061066a610996565b34801561070b57600080fd5b506102a76004803603602081101561072257600080fd5b5035610a5f565b34801561073557600080fd5b506102a7610a6c565b34801561074a57600080fd5b506102a7610a72565b34801561075f57600080fd5b5061026b6004803603602081101561077657600080fd5b50356001600160a01b0316610a78565b600181565b605081565b61200181565b600b5481565b60015481565b600c5481565b600681815481106107b557fe5b6000918252602090912001546001600160a01b0316905081565b61200581565b60076020526000908152604090205481565b61100181565b6102ca81565b61200681565b61200081565b61100581565b6000805460ff1661085d576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604482015290519081900360640190fd5b336120001461089d5760405162461bcd60e51b815260040180806020018281038252602f815260200180610ab9602f913960400191505060405180910390fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b60035481565b61100881565b600581565b61200381565b60056020526000908152604090205481565b61100781565b61100681565b600a5481565b60005460ff1681565b60045481565b61200281565b61300081565b600081565b336110071461089d5760405162461bcd60e51b815260040180806020018281038252602e815260200180610a8b602e913960400191505060405180910390fd5b60025481565b61100281565b600e5481565b61100381565b60095481565b61200481565b60005460ff16156109ee576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b60005460ff1615610a3c576040805162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b604482015290519081900360640190fd5b60018080556005600255600381905560506004556000805460ff19169091179055565b600881815481106107b557fe5b61100081565b61100481565b600d602052600090815260409020548156fe746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001006": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c80639dc092621161011a578063dc927faf116100ad578063e79a198f1161007c578063e79a198f1461047e578063f3ae241514610486578063f9a2bbc7146104ac578063fd30d9b8146104b4578063fd6a6879146104bc576101fb565b8063dc927faf14610466578063dd91d1c514610200578063df8079e91461046e578063e1c7392a14610476576101fb565b8063aad56063116100e9578063aad5606314610373578063ab51bb961461037b578063ac4317511461039c578063c81b16621461045e576101fb565b80639dc0926214610353578063a1a11bf51461035b578063a78abc1614610363578063aa82dce11461036b576101fb565b80636a6a419e116101925780637ae23088116101615780637ae23088146103035780637e434d541461031d5780638f83ab131461032557806395468d261461034b576101fb565b80636a6a419e146102a75780636e47b482146102cd57806375d47a0a146102d557806378beee67146102dd576101fb565b8063493279b1116101ce578063493279b11461023e57806351b4dce31461025d57806351e8067214610265578063541d55481461026d576101fb565b806303aff02b146102005780630e2374a51461020a578063280870281461022e57806343756e5c14610236575b600080fd5b6102086104c4565b005b6102126104fe565b604080516001600160a01b039092168252519081900360200190f35b610212610504565b61021261050a565b610246610510565b6040805161ffff9092168252519081900360200190f35b610212610516565b61021261051c565b6102936004803603602081101561028357600080fd5b50356001600160a01b0316610522565b604080519115158252519081900360200190f35b610293600480360360208110156102bd57600080fd5b50356001600160a01b0316610540565b61021261055e565b610212610564565b610208600480360360208110156102f357600080fd5b50356001600160a01b031661056a565b61030b6105b8565b60408051918252519081900360200190f35b6102126105c5565b6102086004803603602081101561033b57600080fd5b50356001600160a01b03166105cb565b61030b610628565b610212610634565b61021261063a565b610293610640565b610212610649565b61021261064f565b610383610655565b6040805163ffffffff9092168252519081900360200190f35b610208600480360360408110156103b257600080fd5b8101906020810181356401000000008111156103cd57600080fd5b8201836020820111156103df57600080fd5b8035906020019184600183028401116401000000008311171561040157600080fd5b91939092909160208101903564010000000081111561041f57600080fd5b82018360208201111561043157600080fd5b8035906020019184600183028401116401000000008311171561045357600080fd5b50909250905061065a565b6102126106ed565b6102126106f3565b6102126106f9565b6102086106ff565b610208610781565b6102936004803603602081101561049c57600080fd5b50356001600160a01b031661093a565b610212610958565b61029361095e565b610212610967565b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b61200181565b61200581565b61100181565b6102ca81565b61200681565b61200081565b6001600160a01b031660009081526007602052604090205460ff1690565b6001600160a01b031660009081526008602052604090205460ff1690565b61100581565b61100881565b3360009081526008602052604090205460ff166104c45760405162461bcd60e51b8152600401808060200182810382526024815260200180610a686024913960400191505060405180910390fd5b68056bc75e2d6310000081565b61200381565b3360009081526005602052604090205460ff166104c4576040805162461bcd60e51b81526020600482015260166024820152751b585b9859d95c88191bd95cc81b9bdd08195e1a5cdd60521b604482015290519081900360640190fd5b67016345785d8a000081565b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b60005460ff166106ad576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b33611007146104c45760405162461bcd60e51b815260040180806020018281038252602e815260200180610a8c602e913960400191505060405180910390fd5b61100281565b61100381565b61200481565b60005460ff1615610757576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b68056bc75e2d63100000600190815567016345785d8a00006002556000805460ff19169091179055565b3360009081526004602052604090205460ff166107dc576040805162461bcd60e51b81526020600482015260146024820152731c995b185e595c88191bc81b9bdd08195e1a5cdd60621b604482015290519081900360640190fd5b60005460ff1661082f576040805162461bcd60e51b81526020600482015260196024820152781d1a194818dbdb9d1c9858dd081b9bdd081a5b9a5d081e595d603a1b604482015290519081900360640190fd5b610837610a4d565b5033600081815260036020908152604091829020825180840190935280548084526001909101549183018290529192916108fc9161087b919063ffffffff61096d16565b6040518115909202916000818181858888f193505050501580156108a3573d6000803e3d6000fd5b50602081015160405161100291829181156108fc0291906000818181858888f193505050501580156108d9573d6000803e3d6000fd5b50336000818152600460209081526040808320805460ff191690556003825280832083815560010192909255815192835290517fd17202129b83db7880d6b9f25df81c58ad46f7e0e2c92236b1aa10663a4876679281900390910190a15050565b6001600160a01b031660009081526005602052604090205460ff1690565b61100081565b600a5460ff1681565b61100481565b60006109af83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506109b6565b9392505050565b60008184841115610a455760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610a0a5781810151838201526020016109f2565b50505050905090810190601f168015610a375780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60405180604001604052806000815260200160008152509056fe72656c61796572206973206e6f7420612070726f766973696f6e616c2072656c61796572746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001007": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b506004361061018e5760003560e01c80639ab1a373116100de578063ab51bb9611610097578063dc927faf11610071578063dc927faf146104b1578063df8079e9146104b9578063f9a2bbc7146104c1578063fd6a6879146104c95761018e565b8063ab51bb96146104a1578063c81b1662146104a9578063c8509d811461031c5761018e565b80639ab1a3731461045d5780639dc0926214610465578063a1a11bf51461046d578063a78abc1614610475578063aa82dce114610491578063aad56063146104995761018e565b806351b4dce31161014b57806375d47a0a1161012557806375d47a0a1461030c5780637e434d5414610314578063831d65d11461031c57806388e4194e146103965761018e565b806351b4dce3146102f457806351e80672146102fc5780636e47b482146103045761018e565b80630e2374a5146101935780631182b875146101b757806328087028146102a45780633a21baae146102ac57806343756e5c146102cd578063493279b1146102d5575b600080fd5b61019b6104d1565b604080516001600160a01b039092168252519081900360200190f35b61022f600480360360408110156101cd57600080fd5b60ff8235169190810190604081016020820135600160201b8111156101f157600080fd5b82018360208201111561020357600080fd5b803590602001918460018302840111600160201b8311171561022457600080fd5b5090925090506104d7565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610269578181015183820152602001610251565b50505050905090810190601f1680156102965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61019b610513565b6102b4610519565b6040805163ffffffff9092168252519081900360200190f35b61019b61051e565b6102dd610524565b6040805161ffff9092168252519081900360200190f35b61019b61052a565b61019b610530565b61019b610536565b61019b61053c565b61019b610542565b6103946004803603604081101561033257600080fd5b60ff8235169190810190604081016020820135600160201b81111561035657600080fd5b82018360208201111561036857600080fd5b803590602001918460018302840111600160201b8311171561038957600080fd5b509092509050610548565b005b610394600480360360608110156103ac57600080fd5b810190602081018135600160201b8111156103c657600080fd5b8201836020820111156103d857600080fd5b803590602001918460018302840111600160201b831117156103f957600080fd5b919390929091602081019035600160201b81111561041657600080fd5b82018360208201111561042857600080fd5b803590602001918460018302840111600160201b8311171561044957600080fd5b9193509150356001600160a01b03166105c2565b6102b46106ad565b61019b6106b2565b61019b6106b8565b61047d6106be565b604080519115158252519081900360200190f35b61019b6106c7565b61019b6106cd565b6102b46106d3565b61019b6106d8565b61019b6106de565b61019b6106e4565b61019b6106ea565b61019b6106f0565b61200181565b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152905160609181900360640190fd5b61200581565b606681565b61100181565b6102ca81565b61200681565b61200081565b61100581565b61100881565b61200381565b33612000146105885760405162461bcd60e51b815260040180806020018281038252602f815260200180610ac9602f913960400191505060405180910390fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b33612006146106025760405162461bcd60e51b8152600401808060200182810382526031815260200180610af86031913960400191505060405180910390fd5b61060a610a9e565b604051806060016040528087878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250604080516020601f8801819004810282018101909252868152918101919087908790819084018382808284376000920191909152505050908252506001600160a01b03841660209091015290506106a4816106f6565b50505050505050565b606581565b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b61100281565b61100381565b61200481565b61100081565b61100481565b60006107058260400151610a98565b61077157604080516020808252601c908201527f74686520746172676574206973206e6f74206120636f6e7472616374000000008183015290517f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb29181900360600190a1506065610a93565b81604001516001600160a01b031663ac431751836000015184602001516040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b838110156107de5781810151838201526020016107c6565b50505050905090810190601f16801561080b5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101561083e578181015183820152602001610826565b50505050905090810190601f16801561086b5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561088c57600080fd5b505af192505050801561089d575060015b610a8f576040516000815260443d10156108b957506000610956565b60046000803e60005160e01c6308c379a081146108da576000915050610956565b60043d036004833e81513d602482011167ffffffffffffffff8211171561090657600092505050610956565b808301805167ffffffffffffffff811115610928576000945050505050610956565b8060208301013d860181111561094657600095505050505050610956565b601f01601f191660405250925050505b806109615750610a04565b7f70e72399380dcfb0338abc03dc8d47f9f470ada8e769c9a78d644ea97385ecb2816040518080602001828103825283818151815260200191508051906020019080838360005b838110156109c05781810151838201526020016109a8565b50505050905090810190601f1680156109ed5780820380516001836020036101000a031916815260200191505b509250505060405180910390a16066915050610a93565b3d808015610a2e576040519150601f19603f3d011682016040523d82523d6000602084013e610a33565b606091505b5060408051602080825283518183015283517f1279f84165b4fd69c35e1f338ff107231b036c655cd1688851e011ce617c4e8d9385939283929183019190850190808383600083156109c05781810151838201526020016109a8565b5060005b919050565b3b151590565b6040518060600160405280606081526020016060815260200160006001600160a01b03168152509056fe746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d73672073656e646572206d75737420626520676f7665726e6f722074696d656c6f636b20636f6e7472616374a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000001008": { + "balance": "0x0", + "code": "0x6080604052600436106102045760003560e01c80637ec816dd11610118578063ac431751116100a0578063dc927faf1161006f578063dc927faf146108de578063df8079e9146108f3578063e605bca014610908578063f9a2bbc71461091d578063fd6a68791461093257610204565b8063ac4317511461077d578063c81b166214610848578063c8509d811461065f578063d117a1101461085d57610204565b8063a1a11bf5116100e7578063a1a11bf5146106fb578063a78abc1614610710578063aa82dce114610725578063aad560631461073a578063ab51bb961461074f57610204565b80637ec816dd1461064a578063831d65d11461065f57806394553a4e146103345780639dc09262146106e657610204565b8063493279b11161019b5780636e47b4821161016a5780636e47b482146105db57806372c4e086146105f057806375d47a0a1461062057806377d9dae8146105275780637e434d541461063557610204565b8063493279b1146104d157806351b4dce3146104fd57806351e80672146105125780636b3f13071461052757610204565b80632e02d776116101d75780632e02d7761461039357806337e6ecda146103c657806343756e5c146103f9578063445fcefe1461040e57610204565b80630e2374a5146102095780631182b8751461023a57806325c751b714610334578063280870281461037e575b600080fd5b34801561021557600080fd5b5061021e610947565b604080516001600160a01b039092168252519081900360200190f35b34801561024657600080fd5b506102bf6004803603604081101561025d57600080fd5b60ff8235169190810190604081016020820135600160201b81111561028157600080fd5b82018360208201111561029357600080fd5b803590602001918460018302840111600160201b831117156102b457600080fd5b50909250905061094d565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102f95781810151838201526020016102e1565b50505050905090810190601f1680156103265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61036a6004803603604081101561034a57600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff166109c9565b604080519115158252519081900360200190f35b34801561038a57600080fd5b5061021e610a05565b34801561039f57600080fd5b5061036a600480360360208110156103b657600080fd5b50356001600160a01b0316610a0b565b3480156103d257600080fd5b5061036a600480360360208110156103e957600080fd5b50356001600160a01b0316610a20565b34801561040557600080fd5b5061021e610a35565b34801561041a57600080fd5b506104bf6004803603602081101561043157600080fd5b810190602081018135600160201b81111561044b57600080fd5b82018360208201111561045d57600080fd5b803590602001918460018302840111600160201b8311171561047e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610a3b945050505050565b60408051918252519081900360200190f35b3480156104dd57600080fd5b506104e6610b9a565b6040805161ffff9092168252519081900360200190f35b34801561050957600080fd5b5061021e610ba0565b34801561051e57600080fd5b5061021e610ba6565b61036a6004803603604081101561053d57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561056757600080fd5b82018360208201111561057957600080fd5b803590602001918460018302840111600160201b8311171561059a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506109c9945050505050565b3480156105e757600080fd5b5061021e610bac565b61036a6004803603602081101561060657600080fd5b810190602081018135600160201b81111561056757600080fd5b34801561062c57600080fd5b5061021e610bb2565b34801561064157600080fd5b5061021e610bb8565b34801561065657600080fd5b506104bf610bbe565b34801561066b57600080fd5b506106e46004803603604081101561068257600080fd5b60ff8235169190810190604081016020820135600160201b8111156106a657600080fd5b8201836020820111156106b857600080fd5b803590602001918460018302840111600160201b831117156106d957600080fd5b509092509050610bc4565b005b3480156106f257600080fd5b5061021e610c04565b34801561070757600080fd5b5061021e610c0a565b34801561071c57600080fd5b5061036a610c10565b34801561073157600080fd5b5061021e610c19565b34801561074657600080fd5b5061021e610c1f565b34801561075b57600080fd5b50610764610c25565b6040805163ffffffff9092168252519081900360200190f35b34801561078957600080fd5b506106e4600480360360408110156107a057600080fd5b810190602081018135600160201b8111156107ba57600080fd5b8201836020820111156107cc57600080fd5b803590602001918460018302840111600160201b831117156107ed57600080fd5b919390929091602081019035600160201b81111561080a57600080fd5b82018360208201111561081c57600080fd5b803590602001918460018302840111600160201b8311171561083d57600080fd5b509092509050610c2a565b34801561085457600080fd5b5061021e610c6a565b34801561086957600080fd5b506108876004803603602081101561088057600080fd5b5035610c70565b6040805160ff988916815260208101979097526001600160a01b03909516868601526060860193909352608085019190915290931660a083015267ffffffffffffffff90921660c082015290519081900360e00190f35b3480156108ea57600080fd5b5061021e610cc8565b3480156108ff57600080fd5b5061021e610cce565b34801561091457600080fd5b506104bf610cd4565b34801561092957600080fd5b5061021e610cda565b34801561093e57600080fd5b5061021e610ce0565b61200181565b6060336120001461098f5760405162461bcd60e51b815260040180806020018281038252602f815260200180610e31602f913960400191505060405180910390fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152905160009181900360640190fd5b61200581565b60036020526000908152604090205460ff1681565b60026020526000908152604090205460ff1681565b61100181565b6020810151600090610a4b610dc6565b50600081815260016020818152604092839020835160e081018552815460ff9081168252938201549281019290925260028101546001600160a01b031693820184905260038101546060830152600481015460808301526005015491821660a082015261010090910467ffffffffffffffff1660c082015290610ad357600092505050610b95565b600081604001516001600160a01b03166370a082316110046040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015610b3157600080fd5b505afa158015610b45573d6000803e3d6000fd5b505050506040513d6020811015610b5b57600080fd5b505160808301516060840151919250600091610b7c9163ffffffff610ce616565b9050610b8e818363ffffffff610ce616565b9450505050505b919050565b6102ca81565b61200681565b61200081565b61100581565b61100881565b61200381565b60045481565b336120001461098f5760405162461bcd60e51b815260040180806020018281038252602f815260200180610e31602f913960400191505060405180910390fd5b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b336110071461098f5760405162461bcd60e51b815260040180806020018281038252602e815260200180610e03602e913960400191505060405180910390fd5b61100281565b600160208190526000918252604090912080549181015460028201546003830154600484015460059094015460ff9586169593946001600160a01b0390931693919291811690610100900467ffffffffffffffff1687565b61100381565b61200481565b60055481565b61100081565b61100481565b6000610d2883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610d2f565b9392505050565b60008184841115610dbe5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610d83578181015183820152602001610d6b565b50505050905090810190601f168015610db05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091529056fe746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000002000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106102695760003560e01c806375d47a0a11610151578063c81b1662116100c3578063e1c7392a11610087578063e1c7392a14610839578063e3b0480514610841578063e6400bbe14610861578063f7a251d714610869578063f9a2bbc7146108e1578063fd6a6879146108e957610269565b8063c81b1662146107ea578063ccc108d7146107f2578063d31f968d146107fa578063dc927faf14610829578063df8079e91461083157610269565b8063a78abc1611610115578063a78abc16146106d3578063aa82dce1146106db578063aad56063146106e3578063ab51bb96146106eb578063ac4317511461070c578063c27cdcfb146107ca57610269565b806375d47a0a146105d85780637e434d54146105e057806384013b6a146105e85780639dc09262146106c3578063a1a11bf5146106cb57610269565b80633a648b15116101ea57806351e80672116101ae57806351e806721461052a5780635f832177146105325780636bacff2c146105605780636e47a51a146105a85780636e47b482146105c857806374f079b8146105d057610269565b80633a648b15146104b6578063422f9050146104f257806343756e5c14610512578063493279b11461051a57806351b4dce31461052257610269565b806328087028116102315780632808702814610434578063299b533d1461043c5780632af6f399146104705780632ff32aea1461048d578063308325f4146104ae57610269565b80630e2374a51461026e57806314b3023b146102925780631d130935146102ac5780631e275ae1146102c857806322556cdc1461042c575b600080fd5b6102766108f1565b604080516001600160a01b039092168252519081900360200190f35b61029a6108f7565b60408051918252519081900360200190f35b6102b46108fd565b604080519115158252519081900360200190f35b61042a60048036036101008110156102df57600080fd5b81018160a081016080820135600160201b8111156102fc57600080fd5b82018360208201111561030e57600080fd5b803590602001918460018302840111600160201b8311171561032f57600080fd5b919390929091602081019035600160201b81111561034c57600080fd5b82018360208201111561035e57600080fd5b803590602001918460018302840111600160201b8311171561037f57600080fd5b919390929091602081019035600160201b81111561039c57600080fd5b8201836020820111156103ae57600080fd5b803590602001918460018302840111600160201b831117156103cf57600080fd5b919390929091602081019035600160201b8111156103ec57600080fd5b8201836020820111156103fe57600080fd5b803590602001918460018302840111600160201b8311171561041f57600080fd5b509092509050610906565b005b61029a610ba7565b610276610bac565b6104596004803603602081101561045257600080fd5b5035610bb2565b6040805161ffff9092168252519081900360200190f35b6102b46004803603602081101561048657600080fd5b5035610bc8565b610495610bdd565b60408051600792830b90920b8252519081900360200190f35b61029a610be6565b6104d6600480360360208110156104cc57600080fd5b503560ff16610bec565b604080516001600160401b039092168252519081900360200190f35b6102b46004803603602081101561050857600080fd5b503560ff16610c07565b610276610c1c565b610459610c22565b610276610c28565b610276610c2e565b61042a6004803603604081101561054857600080fd5b506001600160a01b0381358116916020013516610c34565b61057d6004803603602081101561057657600080fd5b5035610dad565b6040805161ffff90941684526001600160801b03909216602084015282820152519081900360600190f35b610276600480360360208110156105be57600080fd5b503560ff16610ddc565b610276610df7565b61029a610dfd565b610276610e03565b610276610e09565b61042a600480360360a08110156105fe57600080fd5b810190602081018135600160201b81111561061857600080fd5b82018360208201111561062a57600080fd5b803590602001918460018302840111600160201b8311171561064b57600080fd5b919390929091602081019035600160201b81111561066857600080fd5b82018360208201111561067a57600080fd5b803590602001918460018302840111600160201b8311171561069b57600080fd5b919350915080356001600160401b03908116916020810135909116906040013560ff16610e0f565b6102766111c3565b6102766111c9565b6102b46111cf565b6102766111d8565b6102766111de565b6106f36111e4565b6040805163ffffffff9092168252519081900360200190f35b61042a6004803603604081101561072257600080fd5b810190602081018135600160201b81111561073c57600080fd5b82018360208201111561074e57600080fd5b803590602001918460018302840111600160201b8311171561076f57600080fd5b919390929091602081019035600160201b81111561078c57600080fd5b82018360208201111561079e57600080fd5b803590602001918460018302840111600160201b831117156107bf57600080fd5b5090925090506111e9565b6104d6600480360360208110156107e057600080fd5b503560ff16611229565b610276611244565b61042a61124a565b6102b46004803603604081101561081057600080fd5b5080356001600160a01b0316906020013560ff1661140a565b61027661142a565b610276611430565b61042a611436565b6104d66004803603602081101561085757600080fd5b503560ff166114c8565b61042a6114e3565b61042a6004803603606081101561087f57600080fd5b60ff8235169190810190604081016020820135600160201b8111156108a357600080fd5b8201836020820111156108b557600080fd5b803590602001918460018302840111600160201b831117156108d657600080fd5b91935091503561165c565b6102766116fe565b610276611704565b61200181565b60015481565b600b5460ff1681565b60005460ff1661094b576040805162461bcd60e51b8152602060048201526019602482015260008051602061176a833981519152604482015290519081900360640190fd5b604080516337d7f9c160e21b81526001600160401b038b35166004820181905291516110039163df5fe704916024808301926020929190829003018186803b15801561099657600080fd5b505afa1580156109aa573d6000803e3d6000fd5b505050506040513d60208110156109c057600080fd5b50516109fd5760405162461bcd60e51b815260040180806020018281038252602381526020018061178a6023913960400191505060405180910390fd5b604080516337d7f9c160e21b815260208c8101356001600160401b03166004830181905292516110039263df5fe704926024808301939192829003018186803b158015610a4957600080fd5b505afa158015610a5d573d6000803e3d6000fd5b505050506040513d6020811015610a7357600080fd5b5051610ab05760405162461bcd60e51b815260040180806020018281038252602381526020018061178a6023913960400191505060405180910390fd5b60608b013560ff81166000908152600560205260409020546001600160401b03909116906001600160a01b0316610b29576040805162461bcd60e51b815260206004820152601860248201527718da185b9b995b081a5cc81b9bdd081cdd5c1c1bdc9d195960421b604482015290519081900360640190fd5b600b5460ff1615610b6d576040805162461bcd60e51b81526020600482015260096024820152681cdd5cdc195b99195960ba1b604482015290519081900360640190fd5b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b603281565b61200581565b600d6020526000908152604090205461ffff1681565b600e6020526000908152604090205460ff1681565b60045460070b81565b60025481565b600a602052600090815260409020546001600160401b031681565b60096020526000908152604090205460ff1681565b61100181565b6102ca81565b61200681565b61200081565b60005460ff16610c79576040805162461bcd60e51b8152602060048201526019602482015260008051602061176a833981519152604482015290519081900360640190fd5b6040805163569e4ed360e11b815233600482015290516000916110009163ad3c9da691602480820192602092909190829003018186803b158015610cbc57600080fd5b505afa158015610cd0573d6000803e3d6000fd5b505050506040513d6020811015610ce657600080fd5b505160408051633d42651560e11b8152905191925060009161100091637a84ca2a916004808301926020929190829003018186803b158015610d2757600080fd5b505afa158015610d3b573d6000803e3d6000fd5b505050506040513d6020811015610d5157600080fd5b5051905080610d5e575060155b600082118015610d6e5750808211155b610b6d576040805162461bcd60e51b815260206004820152600b60248201526a1b9bdd0818d8589a5b995d60aa1b604482015290519081900360640190fd5b600c602052600090815260409020805460019091015461ffff8216916201000090046001600160801b03169083565b6005602052600090815260409020546001600160a01b031681565b61100581565b60035481565b61100881565b61200381565b60005460ff16610e54576040805162461bcd60e51b8152602060048201526019602482015260008051602061176a833981519152604482015290519081900360640190fd5b60408051630a83aaa960e31b815233600482015290516110069163541d5548916024808301926020929190829003018186803b158015610e9357600080fd5b505afa158015610ea7573d6000803e3d6000fd5b505050506040513d6020811015610ebd57600080fd5b5051610f10576040805162461bcd60e51b815260206004820152601f60248201527f746865206d73672073656e646572206973206e6f7420612072656c6179657200604482015290519081900360640190fd5b60ff8116600090815260086020526040902054829082906001600160401b039081169083168114610f80576040805162461bcd60e51b815260206004820152601560248201527439b2b8bab2b731b2903737ba1034b71037b93232b960591b604482015290519081900360640190fd5b60ff8216600090815260086020908152604091829020805467ffffffffffffffff1916600185016001600160401b039081169190911790915582516337d7f9c160e21b81529089166004820152915188926110039263df5fe70492602480840193829003018186803b158015610ff557600080fd5b505afa158015611009573d6000803e3d6000fd5b505050506040513d602081101561101f57600080fd5b505161105c5760405162461bcd60e51b815260040180806020018281038252602381526020018061178a6023913960400191505060405180910390fd5b60ff851660009081526005602052604090205485906001600160a01b03166110c6576040805162461bcd60e51b815260206004820152601860248201527718da185b9b995b081a5cc81b9bdd081cdd5c1c1bdc9d195960421b604482015290519081900360640190fd5b60ff86166000908152600a6020526040902054889087906001600160401b03908116908316101561112f576040805162461bcd60e51b815260206004820152600e60248201526d3a37b79037b632103432b0b232b960911b604482015290519081900360640190fd5b60ff81166000908152600a60205260409020546001600160401b03838116911614610b295760ff8181166000908152600a60205260409020805467ffffffffffffffff19166001600160401b038516179055600b541615610b6d576040805162461bcd60e51b81526020600482015260096024820152681cdd5cdc195b99195960ba1b604482015290519081900360640190fd5b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b3361100714610b295760405162461bcd60e51b815260040180806020018281038252602e81526020018061173c602e913960400191505060405180910390fd5b6008602052600090815260409020546001600160401b031681565b61100281565b60005460ff1661128f576040805162461bcd60e51b8152602060048201526019602482015260008051602061176a833981519152604482015290519081900360640190fd5b6040805163569e4ed360e11b815233600482015290516000916110009163ad3c9da691602480820192602092909190829003018186803b1580156112d257600080fd5b505afa1580156112e6573d6000803e3d6000fd5b505050506040513d60208110156112fc57600080fd5b505160408051633d42651560e11b8152905191925060009161100091637a84ca2a916004808301926020929190829003018186803b15801561133d57600080fd5b505afa158015611351573d6000803e3d6000fd5b505050506040513d602081101561136757600080fd5b5051905080611374575060155b6000821180156113845750808211155b6113c3576040805162461bcd60e51b815260206004820152600b60248201526a1b9bdd0818d8589a5b995d60aa1b604482015290519081900360640190fd5b600b5460ff16610b6d576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd081cdd5cdc195b991959609a1b604482015290519081900360640190fd5b600660209081526000928352604080842090915290825290205460ff1681565b61100381565b61200481565b60005460ff161561148e576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b603260019081556004805467ffffffffffffffff19166001600160401b03179055600060028190556003819055805460ff19169091179055565b6007602052600090815260409020546001600160401b031681565b60005460ff16611528576040805162461bcd60e51b8152602060048201526019602482015260008051602061176a833981519152604482015290519081900360640190fd5b6040805163569e4ed360e11b815233600482015290516000916110009163ad3c9da691602480820192602092909190829003018186803b15801561156b57600080fd5b505afa15801561157f573d6000803e3d6000fd5b505050506040513d602081101561159557600080fd5b505160408051633d42651560e11b8152905191925060009161100091637a84ca2a916004808301926020929190829003018186803b1580156115d657600080fd5b505afa1580156115ea573d6000803e3d6000fd5b505050506040513d602081101561160057600080fd5b505190508061160d575060155b60008211801561161d5750808211155b610b29576040805162461bcd60e51b815260206004820152600b60248201526a1b9bdd0818d8589a5b995d60aa1b604482015290519081900360640190fd5b60005460ff166116a1576040805162461bcd60e51b8152602060048201526019602482015260008051602061176a833981519152604482015290519081900360640190fd5b33600090815260066020908152604080832060ff8089168552925290912054859116610b6d5760405162461bcd60e51b815260040180806020018281038252603181526020018061170b6031913960400191505060405180910390fd5b61100081565b6110048156fe74686520636f6e747261637420616e64206368616e6e656c2068617665206e6f74206265656e2072656769737465726564746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e747261637474686520636f6e7472616374206e6f7420696e697420796574000000000000006c6967687420636c69656e74206e6f742073796e632074686520626c6f636b20796574a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000002001": { + "balance": "0x0", + "code": "0x60806040526004361061028c5760003560e01c806375d47a0a1161015a578063bf8546ca116100c1578063df8079e91161007a578063df8079e9146109aa578063edc1a5b0146109bf578063f45fd80b146109d4578063f9a2bbc714610a19578063fa03f79714610a2e578063fd6a687914610a4357610293565b8063bf8546ca146108f5578063c2117d8214610930578063c81b166214610945578063c8509d81146106d0578063d61b9b931461095a578063dc927faf1461099557610293565b8063aa82dce111610113578063aa82dce1146107a8578063aad56063146107bd578063ab51bb96146107d2578063ac43175114610800578063b88a802f146108cb578063baaafd3b146108e057610293565b806375d47a0a146106a65780637e434d54146106bb578063831d65d1146106d05780639dc0926214610755578063a1a11bf51461076a578063a78abc161461077f57610293565b8063493279b1116101fe57806362b171d2116101b757806362b171d2146105cb57806369b635b6146105e05780636bd8f804146105f55780636e47b4821461062b5780636fb7f7eb1461064057806375aca5931461067357610293565b8063493279b11461051f5780634d99dd161461054b57806351b4dce31461057757806351e806721461058c5780635d17c8bd146105a15780635d499b1b146105b657610293565b80631182b875116102505780631182b8751461039e57806311fe9ec61461049857806328087028146104cb5780632fdeb111146104e057806334c43354146104f557806343756e5c1461050a57610293565b8063026e402b1461029857806302985992146102c6578063047636d1146102ed5780630c795715146103585780630e2374a51461036d57610293565b3661029357005b600080fd5b6102c4600480360360408110156102ae57600080fd5b506001600160a01b038135169060200135610a58565b005b3480156102d257600080fd5b506102db610a95565b60408051918252519081900360200190f35b3480156102f957600080fd5b506103206004803603602081101561031057600080fd5b50356001600160a01b0316610a9b565b6040518082606080838360005b8381101561034557818101518382015260200161032d565b5050505090500191505060405180910390f35b34801561036457600080fd5b506102db610aed565b34801561037957600080fd5b50610382610af3565b604080516001600160a01b039092168252519081900360200190f35b3480156103aa57600080fd5b50610423600480360360408110156103c157600080fd5b60ff8235169190810190604081016020820135600160201b8111156103e557600080fd5b8201836020820111156103f757600080fd5b803590602001918460018302840111600160201b8311171561041857600080fd5b509092509050610af9565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561045d578181015183820152602001610445565b50505050905090810190601f16801561048a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104a457600080fd5b506102db600480360360208110156104bb57600080fd5b50356001600160a01b0316610bb8565b3480156104d757600080fd5b50610382610bd3565b3480156104ec57600080fd5b506102db610bd9565b34801561050157600080fd5b506102db610bdf565b34801561051657600080fd5b50610382610bea565b34801561052b57600080fd5b50610534610bf0565b6040805161ffff9092168252519081900360200190f35b6102c46004803603604081101561056157600080fd5b506001600160a01b038135169060200135610bf6565b34801561058357600080fd5b50610382610cbb565b34801561059857600080fd5b50610382610cc1565b3480156105ad57600080fd5b506102db610cc7565b3480156105c257600080fd5b506102db610ccd565b3480156105d757600080fd5b506102db610cd6565b3480156105ec57600080fd5b506102db610e76565b6102c46004803603606081101561060b57600080fd5b506001600160a01b03813581169160208101359091169060400135610a58565b34801561063757600080fd5b50610382610e7c565b34801561064c57600080fd5b506102db6004803603602081101561066357600080fd5b50356001600160a01b0316610e82565b34801561067f57600080fd5b506102db6004803603602081101561069657600080fd5b50356001600160a01b0316610e9d565b3480156106b257600080fd5b50610382610eb8565b3480156106c757600080fd5b50610382610ebe565b3480156106dc57600080fd5b506102c4600480360360408110156106f357600080fd5b60ff8235169190810190604081016020820135600160201b81111561071757600080fd5b82018360208201111561072957600080fd5b803590602001918460018302840111600160201b8311171561074a57600080fd5b509092509050610ec4565b34801561076157600080fd5b50610382610f04565b34801561077657600080fd5b50610382610f0a565b34801561078b57600080fd5b50610794610f10565b604080519115158252519081900360200190f35b3480156107b457600080fd5b50610382610f19565b3480156107c957600080fd5b50610382610f1f565b3480156107de57600080fd5b506107e7610f25565b6040805163ffffffff9092168252519081900360200190f35b34801561080c57600080fd5b506102c46004803603604081101561082357600080fd5b810190602081018135600160201b81111561083d57600080fd5b82018360208201111561084f57600080fd5b803590602001918460018302840111600160201b8311171561087057600080fd5b919390929091602081019035600160201b81111561088d57600080fd5b82018360208201111561089f57600080fd5b803590602001918460018302840111600160201b831117156108c057600080fd5b509092509050610f2a565b3480156108d757600080fd5b506102db610fc1565b3480156108ec57600080fd5b506102db61115e565b34801561090157600080fd5b506102db6004803603604081101561091857600080fd5b506001600160a01b0381358116916020013516611169565b34801561093c57600080fd5b506102db611194565b34801561095157600080fd5b5061038261119a565b34801561096657600080fd5b506102db6004803603604081101561097d57600080fd5b506001600160a01b03813581169160200135166111a0565b3480156109a157600080fd5b506103826111cb565b3480156109b657600080fd5b506103826111d1565b3480156109cb57600080fd5b506102db6111d7565b3480156109e057600080fd5b506102db600480360360608110156109f757600080fd5b506001600160a01b0381358116916020810135821691604090910135166111e4565b348015610a2557600080fd5b50610382611219565b348015610a3a57600080fd5b506102db61121f565b348015610a4f57600080fd5b50610382611225565b6040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd081cdd5c1c1bdc9d1959609a1b604482015290519081900360640190fd5b60035481565b610aa361122b565b610aab61122b565b6001600160a01b03929092166000818152600b60209081526040808320548652838352600c82528083205486830152928252600d905281902054908301525090565b6108fc81565b61200181565b60603361200014610b3b5760405162461bcd60e51b815260040180806020018281038252602f815260200180611278602f913960400191505060405180910390fd5b60005460ff16610b7e576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b6040805162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b604482015290519081900360640190fd5b6001600160a01b031660009081526006602052604090205490565b61200581565b60015481565b662386f26fc1000081565b61100181565b6102ca81565b60105460ff1660021415610c42576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b6010805460ff19166002179055806402540be4003406158015610c6a57506402540be4008106155b610b3b576040805162461bcd60e51b815260206004820152601c60248201527f707265636973696f6e206c6f737320696e20636f6e76657273696f6e00000000604482015290519081900360640190fd5b61200681565b61200081565b60025481565b6402540be40081565b60105460009060ff1660021415610d25576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b506010805460ff191660021790553360009081526008602052604090205480610d8c576040805162461bcd60e51b81526020600482015260146024820152736e6f20756e64656c6567617465642066756e647360601b604482015290519081900360640190fd5b336000818152600860205260408082208290556011549051919291849084818181858888f193505050503d8060008114610de2576040519150601f19603f3d011682016040523d82523d6000602084013e610de7565b606091505b5050905080610e2f576040805162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b60408051838152905133917fc712d133b8d448221aaed2198ed1f0db6dfc860fb01bc3a630916fe6cbef946f919081900360200190a2506010805460ff1916600117905590565b60035490565b61100581565b6001600160a01b031660009081526004602052604090205490565b6001600160a01b031660009081526008602052604090205490565b61100881565b61200381565b3361200014610b3b5760405162461bcd60e51b815260040180806020018281038252602f815260200180611278602f913960400191505060405180910390fd5b61100781565b61100681565b60005460ff1681565b61200281565b61300081565b600081565b60005460ff16610f81576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604482015290519081900360640190fd5b3361100714610b7e5760405162461bcd60e51b815260040180806020018281038252602e81526020018061124a602e913960400191505060405180910390fd5b60105460009060ff1660021415611010576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b506010805460ff191660021790553360009081526006602052604090205480611074576040805162461bcd60e51b81526020600482015260116024820152701b9bc81c195b991a5b99c81c995dd85c99607a1b604482015290519081900360640190fd5b336000818152600660205260408082208290556011549051919291849084818181858888f193505050503d80600081146110ca576040519150601f19603f3d011682016040523d82523d6000602084013e6110cf565b606091505b5050905080611117576040805162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b60408051838152905133917f83b78188b13346b2ffb484da70d42ee27de7fbf9f2bd8045269e10ed643ccd76919081900360200190a2506010805460ff1916600117905590565b6638d7ea4c68000081565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205490565b60015490565b61100281565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205490565b61100381565b61200481565b68056bc75e2d6310000081565b6001600160a01b0392831660009081526009602090815260408083209486168352938152838220929094168152925290205490565b61100081565b60115481565b61100481565b6040518060600160405280600390602082028036833750919291505056fe746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374a164736f6c6343000604000a" + }, + "0x0000000000000000000000000000000000002002": { + "balance": "0x0", + "code": "0x6080604052600436106200043b5760003560e01c806386d545061162000233578063ca47908f116200012f578063dd42a1dd11620000b9578063f1f74d841162000084578063f1f74d841462000d74578063f80a34021462000d8c578063fb50b31f1462000db1578063fc0c5ff11462000dd6578063ff69ab611462000dee57600080fd5b8063dd42a1dd1462000ce1578063e8f67c3b1462000d08578063e992aaf51462000d20578063efdbf0e11462000d3857600080fd5b8063d7c2dfc811620000fa578063d7c2dfc81462000c67578063d8ca511f1462000c8c578063daacdb661462000ca4578063dbda7fb31462000cbc57600080fd5b8063ca47908f1462000bd0578063cbb04d9d1462000be8578063d115a2061462000c29578063d6ca429d1462000c4257600080fd5b8063b187bd2611620001bd578063bfff04751162000188578063bfff04751462000b57578063c166f58a1462000b7c578063c38fbec81462000b93578063c473318f1462000bb8578063c8509d81146200095057600080fd5b8063b187bd261462000ac4578063baa7199e1462000ae4578063bdceadf31462000b09578063bff02e201462000b2157600080fd5b8063a1832e6411620001fe578063a1832e641462000a21578063a43569b31462000a46578063aad3ec961462000a7a578063ac4317511462000a9f57600080fd5b806386d54506146200098d5780638a4d3fa814620009c75780638cd22b2214620009e5578063982ef0a71462000a0a57600080fd5b80634838d165116200034357806364028fbd11620002cd57806375cc7d89116200029857806375cc7d8914620008fb57806376e7d6d614620009205780638129fc1c1462000938578063831d65d114620009505780638456cb59146200097557600080fd5b806364028fbd1462000836578063663706d3146200084d5780636ec01b27146200087e5780636f8e2fa414620008d657600080fd5b80634e6fd6c4116200030e5780634e6fd6c4146200079d5780635949187114620007b55780635e7cc1c914620007da57806363a036b514620007ff57600080fd5b80634838d16514620006e957806349f41a42146200072e5780634a49ac4c14620007535780634d99dd16146200077857600080fd5b80631fab701511620003c5578063384099881162000390578063384099881462000662578063417c73a7146200067a578063449ecfe6146200069f57806345211bfd14620006c457600080fd5b80631fab701514620005a95780632b727c8614620005ce5780632e8e8c7114620005f3578063367dad49146200062d57600080fd5b80630e9fbf5111620004065780630e9fbf5114620004f35780631182b875146200051857806317b4f353146200054c5780631fa8882b146200059157600080fd5b8063046f7da2146200045b578063059ddd2214620004735780630661806e14620004b5578063092193ab14620004dc57600080fd5b36620004565760345460ff166001146200045457600080fd5b005b600080fd5b3480156200046857600080fd5b506200045462000e06565b3480156200048057600080fd5b506200049862000492366004620096e4565b62000e98565b6040516001600160a01b0390911681526020015b60405180910390f35b348015620004c257600080fd5b50620004cd60365481565b604051908152602001620004ac565b62000454620004ed366004620096e4565b620012c0565b3480156200050057600080fd5b50620004546200051236600462009746565b62001911565b3480156200052557600080fd5b506200053d620005373660046200978b565b62001c3b565b604051620004ac91906200983e565b3480156200055957600080fd5b50620004986200056b36600462009910565b80516020818301810180516045825292820191909301209152546001600160a01b031681565b3480156200059e57600080fd5b50620004cd61025881565b348015620005b657600080fd5b5062000454620005c8366004620099ac565b62001cd3565b348015620005db57600080fd5b5062000498620005ed366004620096e4565b6200202a565b3480156200060057600080fd5b506200049862000612366004620096e4565b604d602052600090815260409020546001600160a01b031681565b3480156200063a57600080fd5b50620006526200064c366004620099ac565b6200207f565b604051620004ac92919062009a2b565b3480156200066f57600080fd5b50620004cd60375481565b3480156200068757600080fd5b506200045462000699366004620096e4565b6200264e565b348015620006ac57600080fd5b5062000454620006be366004620096e4565b620026d0565b348015620006d157600080fd5b5062000454620006e3366004620096e4565b620028b5565b348015620006f657600080fd5b506200071d62000708366004620096e4565b60016020526000908152604090205460ff1681565b6040519015158152602001620004ac565b3480156200073b57600080fd5b50620004546200074d366004620096e4565b62002a8d565b3480156200076057600080fd5b506200045462000772366004620096e4565b62002ca9565b3480156200078557600080fd5b50620004546200079736600462009aca565b62002d25565b348015620007aa57600080fd5b506200049861dead81565b348015620007c257600080fd5b5062000454620007d436600462009b08565b62003355565b348015620007e757600080fd5b5062000454620007f936600462009b72565b6200414e565b3480156200080c57600080fd5b50620008246200081e36600462009b99565b62004377565b604051620004ac949392919062009bbc565b620004546200084736600462009c78565b62004a1c565b3480156200085a57600080fd5b50620004cd6200086c366004620096e4565b60446020526000908152604090205481565b3480156200088b57600080fd5b50620008a36200089d366004620096e4565b6200506b565b6040805182516001600160401b0390811682526020808501518216908301529282015190921690820152606001620004ac565b348015620008e357600080fd5b506200053d620008f5366004620096e4565b62005110565b3480156200090857600080fd5b50620004546200091a366004620096e4565b6200553c565b3480156200092d57600080fd5b50620004cd603d5481565b3480156200094557600080fd5b50620004546200570e565b3480156200095d57600080fd5b50620004546200096f3660046200978b565b620058d6565b3480156200098257600080fd5b506200045462005934565b3480156200099a57600080fd5b5062000498620009ac366004620096e4565b6043602052600090815260409020546001600160a01b031681565b348015620009d457600080fd5b50620004cd670de0b6b3a764000081565b348015620009f257600080fd5b50620004cd62000a0436600462009aca565b620059cc565b6200045462000a1b36600462009d4e565b62005a85565b34801562000a2e57600080fd5b506200045462000a40366004620099ac565b62006133565b34801562000a5357600080fd5b5062000a6b62000a65366004620096e4565b62006439565b604051620004ac919062009d86565b34801562000a8757600080fd5b506200045462000a9936600462009aca565b62006726565b34801562000aac57600080fd5b506200045462000abe36600462009e03565b62006793565b34801562000ad157600080fd5b5060005462010000900460ff166200071d565b34801562000af157600080fd5b506200045462000b0336600462009e75565b62007745565b34801562000b1657600080fd5b50620004cd603c5481565b34801562000b2e57600080fd5b5062000b4662000b4036600462009b99565b62007912565b604051620004ac9392919062009ece565b34801562000b6457600080fd5b50620004cd62000b76366004620096e4565b62007aee565b34801562000b8957600080fd5b50620004cd600581565b34801562000ba057600080fd5b506200045462000bb2366004620096e4565b62007b3c565b34801562000bc557600080fd5b50620004cd60385481565b34801562000bdd57600080fd5b50620004cd604e5481565b34801562000bf557600080fd5b5062000c0d62000c07366004620096e4565b62007dfc565b60408051938452911515602084015290820152606001620004ac565b34801562000c3657600080fd5b50620004cd620186a081565b34801562000c4f57600080fd5b506200045462000c6136600462009f2b565b6200823f565b34801562000c7457600080fd5b506200045462000c863660046200a014565b62008464565b34801562000c9957600080fd5b50620004cd603b5481565b34801562000cb157600080fd5b50620004cd60495481565b34801562000cc957600080fd5b506200049862000cdb366004620096e4565b6200855a565b34801562000cee57600080fd5b50600054630100000090046001600160a01b031662000498565b34801562000d1557600080fd5b50620004cd60355481565b34801562000d2d57600080fd5b50620004cd603a5481565b34801562000d4557600080fd5b50620004cd62000d5736600462009910565b805160208183018101805160468252928201919093012091525481565b34801562000d8157600080fd5b50620004cd603e5481565b34801562000d9957600080fd5b50620004cd62000dab36600462009aca565b62008984565b34801562000dbe57600080fd5b506200045462000dd036600462009e03565b620089f5565b34801562000de357600080fd5b50620004cd60395481565b34801562000dfb57600080fd5b50620004cd604a5481565b600054630100000090046001600160a01b0316331462000e39576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1662000e6357604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384939091608084019162000f03906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462000f31906200a07a565b801562000f825780601f1062000f565761010080835404028352916020019162000f82565b820191906000526020600020905b81548152906001019060200180831162000f6457829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462000fad906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462000fdb906200a07a565b80156200102c5780601f1062001000576101008083540402835291602001916200102c565b820191906000526020600020905b8154815290600101906020018083116200100e57829003601f168201915b5050505050815260200160018201805462001047906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462001075906200a07a565b8015620010c65780601f106200109a57610100808354040283529160200191620010c6565b820191906000526020600020905b815481529060010190602001808311620010a857829003601f168201915b50505050508152602001600282018054620010e1906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200110f906200a07a565b8015620011605780601f10620011345761010080835404028352916020019162001160565b820191906000526020600020905b8154815290600101906020018083116200114257829003601f168201915b505050505081526020016003820180546200117b906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620011a9906200a07a565b8015620011fa5780601f10620011ce57610100808354040283529160200191620011fa565b820191906000526020600020905b815481529060010190602001808311620011dc57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162001299575050509190925250509051949350505050565b3361100014620012ec57604051630f22c43960e41b815261100060048201526024015b60405180910390fd5b6001600160a01b0380821660009081526043602090815260408083205484168084526041835281842082516101808101845281548716815260018201548716948101949094526002810154909516918301919091526003840154606083015260048401805491949160808401919062001365906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462001393906200a07a565b8015620013e45780601f10620013b857610100808354040283529160200191620013e4565b820191906000526020600020905b815481529060010190602001808311620013c657829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200140f906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200143d906200a07a565b80156200148e5780601f1062001462576101008083540402835291602001916200148e565b820191906000526020600020905b8154815290600101906020018083116200147057829003601f168201915b50505050508152602001600182018054620014a9906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620014d7906200a07a565b8015620015285780601f10620014fc5761010080835404028352916020019162001528565b820191906000526020600020905b8154815290600101906020018083116200150a57829003601f168201915b5050505050815260200160028201805462001543906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462001571906200a07a565b8015620015c25780601f106200159657610100808354040283529160200191620015c2565b820191906000526020600020905b815481529060010190602001808311620015a457829003601f168201915b50505050508152602001600382018054620015dd906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200160b906200a07a565b80156200165c5780601f1062001630576101008083540402835291602001916200165c565b820191906000526020600020905b8154815290600101906020018083116200163e57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620016fb575050509190925250505060408101519091506001600160a01b031615806200173857508060e001515b15620017f557604051611002903490600081818185875af1925050503d806000811462001782576040519150601f19603f3d011682016040523d82523d6000602084013e62001787565b606091505b505050816001600160a01b03167ffc8bff675087dd2da069cc3fb517b9ed001e19750c0865241a5542dba1ba170d604051620017e89060208082526011908201527024a72b20a624a22fab20a624a220aa27a960791b604082015260600190565b60405180910390a2505050565b60408181015160c0830151519151632f303ebb60e11b81526001600160401b0390921660048301526001600160a01b031690635e607d769034906024016000604051808303818588803b1580156200184c57600080fd5b505af115801562001861573d6000803e3d6000fd5b5050505050816001600160a01b03167fe34918ff1c7084970068b53fd71ad6d8b04e9f15d3886cbf006443e6cdc52ea634604051620018a291815260200190565b60405180910390a26040808201519051633041949b60e01b815261200591633041949b91620018d7919086906004016200a0b0565b600060405180830381600087803b158015620018f257600080fd5b505af115801562001907573d6000803e3d6000fd5b5050505050505b50565b33611001146200193957604051630f22c43960e41b81526110016004820152602401620012e3565b60005462010000900460ff16156200196457604051631785c68160e01b815260040160405180910390fd5b6000604583836040516200197a9291906200a0ca565b908152604051908190036020019020546001600160a01b03169050620019a2603f8262008c2d565b620019c05760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038116600090815260416020526040812090620019e7610258426200a0f0565b604a546000828152604b60205260409020549192501162001a1b5760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062001a3c9084906200a113565b909155505060405160469062001a5690879087906200a0ca565b90815260200160405180910390205460001415801562001aa65750426102586046878760405162001a899291906200a0ca565b90815260200160405180910390205462001aa491906200a113565b105b1562001ac557604051631898eb6b60e01b815260040160405180910390fd5b60008062001ad585600262008c50565b915091508162001af857604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562001b4b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b7191906200a129565b905062001b7f858362008cd8565b856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600260405162001bbf939291906200a143565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b9162001bfd916001600160a01b0316908a906004016200a0b0565b600060405180830381600087803b15801562001c1857600080fd5b505af115801562001c2d573d6000803e3d6000fd5b505050505050505050505050565b6060336120001462001c6557604051630f22c43960e41b81526120006004820152602401620012e3565b60005462010000900460ff161562001c9057604051631785c68160e01b815260040160405180910390fd5b6034805460ff1916600117905560405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e3565b60005462010000900460ff161562001cfe57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562001d305760405163b1d02c3d60e01b815260040160405180910390fd5b62001d3a62008dcc565b62001d47603f8262008c2d565b62001d655760405163056e881160e01b815260040160405180910390fd5b62001d6f62008e17565b600082900362001d9257604051636490ffd360e01b815260040160405180910390fd5b600062001d9e62008dcc565b6001600160a01b0381166000908152604f602052604090208054604e54929350909162001dcc86836200a113565b111562001dec5760405163091af98560e21b815260040160405180910390fd5b60005b8581101562001ed257600087878381811062001e0f5762001e0f6200a17e565b905060200201350362001e3557604051636490ffd360e01b815260040160405180910390fd5b600062001e448260016200a113565b90505b8681101562001ebc5787878281811062001e655762001e656200a17e565b9050602002013588888481811062001e815762001e816200a17e565b905060200201350362001ea757604051632205e3c760e11b815260040160405180910390fd5b8062001eb3816200a194565b91505062001e47565b508062001ec9816200a194565b91505062001def565b5060005b8581101562001f715760005b8281101562001f5b5783818154811062001f005762001f006200a17e565b906000526020600020015488888481811062001f205762001f206200a17e565b905060200201350362001f4657604051632205e3c760e11b815260040160405180910390fd5b8062001f52816200a194565b91505062001ee2565b508062001f68816200a194565b91505062001ed6565b5060005b8581101562001907578287878381811062001f945762001f946200a17e565b835460018101855560009485526020948590209190940292909201359190920155506001600160a01b0384167f7c4ff4c9a343a2daef608f3b5a91016e994a15fc0ef8611109e4f45823249f2988888481811062001ff65762001ff66200a17e565b905060200201356040516200200d91815260200190565b60405180910390a28062002021816200a194565b91505062001f75565b6000816200203a603f8262008c2d565b620020585760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160205260409020600d01541691505b50919050565b60608082806001600160401b038111156200209e576200209e62009853565b604051908082528060200260200182016040528015620020c8578160200160208202803683370190505b509250806001600160401b03811115620020e657620020e662009853565b6040519080825280602002602001820160405280156200211b57816020015b6060815260200190600190039081620021055790505b50915060005b81811015620026445760008686838181106200214157620021416200a17e565b9050602002016020810190620021589190620096e4565b6001600160a01b03808216600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082015260048301805494955091939092916080840191620021c5906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620021f3906200a07a565b8015620022445780601f10620022185761010080835404028352916020019162002244565b820191906000526020600020905b8154815290600101906020018083116200222657829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200226f906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200229d906200a07a565b8015620022ee5780601f10620022c257610100808354040283529160200191620022ee565b820191906000526020600020905b815481529060010190602001808311620022d057829003601f168201915b5050505050815260200160018201805462002309906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462002337906200a07a565b8015620023885780601f106200235c5761010080835404028352916020019162002388565b820191906000526020600020905b8154815290600101906020018083116200236a57829003601f168201915b50505050508152602001600282018054620023a3906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620023d1906200a07a565b8015620024225780601f10620023f65761010080835404028352916020019162002422565b820191906000526020600020905b8154815290600101906020018083116200240457829003601f168201915b505050505081526020016003820180546200243d906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200246b906200a07a565b8015620024bc5780601f106200249057610100808354040283529160200191620024bc565b820191906000526020600020905b8154815290600101906020018083116200249e57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200255b57505050505081525050905080600001518684815181106200259457620025946200a17e565b6001600160a01b039283166020918202929092018101919091529083166000908152604f8252604090819020805482518185028101850190935280835291929091908301828280156200260757602002820191906000526020600020905b815481526020019060010190808311620025f2575b50505050508584815181106200262157620026216200a17e565b6020026020010181905250505080806200263b906200a194565b91505062002121565b50505b9250929050565b600054630100000090046001600160a01b0316331462002681576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60005462010000900460ff1615620026fb57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200272d5760405163b1d02c3d60e01b815260040160405180910390fd5b806200273b603f8262008c2d565b620027595760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0382166000908152604160205260409020600a81015460ff166200279757604051634b6b857d60e01b815260040160405180910390fd5b6036546002820154604051630913db4760e01b81526001600160a01b03868116600483015290911690630913db4790602401602060405180830381865afa158015620027e7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200280d91906200a129565b10156200282d576040516317b204bf60e11b815260040160405180910390fd5b4281600b01541115620028535760405163170cb76760e21b815260040160405180910390fd5b600a8101805460ff191690556049805460019190600090620028779084906200a1b0565b90915550506040516001600160a01b038416907f9390b453426557da5ebdc31f19a37753ca04addf656d32f35232211bb2af3f1990600090a2505050565b60005462010000900460ff1615620028e057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620029125760405163b1d02c3d60e01b815260040160405180910390fd5b6200291c62008e2a565b62002929603f8262008c2d565b620029475760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0382166200296f57604051636520611b60e11b815260040160405180910390fd5b6001600160a01b038281166000908152604360205260409020541615620029a957604051631e6f587560e11b815260040160405180910390fd5b6000620029b562008e2a565b6001600160a01b0381166000908152604160205260409020600c810154919250904290620029e790610258906200a113565b111562002a0757604051631f92cdbd60e11b815260040160405180910390fd5b80546001600160a01b039081166000908152604460209081526040808320429081905585548986166001600160a01b031991821681178855600c88019290925581855260439093528184208054958816959093168517909255519092917f6e4e747ca35203f16401c69805c7dd52fff67ef60b0ebc5c7fe16890530f223591a350505050565b3362002a9b603f8262008c2d565b62002ab95760405163056e881160e01b815260040160405180910390fd5b60005462010000900460ff161562002ae457604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002b165760405163b1d02c3d60e01b815260040160405180910390fd5b6001600160a01b038281166000908152604d6020526040902054161562002b505760405163bebdc75760e01b815260040160405180910390fd5b62002b5d603f8362008c2d565b1562002b7c5760405163bebdc75760e01b815260040160405180910390fd5b336000818152604160205260409020600d01546001600160a01b03908116908416810362002bbd5760405163bebdc75760e01b815260040160405180910390fd5b6001600160a01b0381161562002bf4576001600160a01b0381166000908152604d6020526040902080546001600160a01b03191690555b6001600160a01b038281166000908152604160205260409020600d0180546001600160a01b03191691861691821790551562002c59576001600160a01b038481166000908152604d6020526040902080546001600160a01b0319169184169190911790555b836001600160a01b0316816001600160a01b0316836001600160a01b03167fcbb728765de145e99c00e8ae32a325231e850359b7b8a6da3b84d672ab3f1d0a60405160405180910390a450505050565b600054630100000090046001600160a01b0316331462002cdc576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b60005462010000900460ff161562002d5057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562002d825760405163b1d02c3d60e01b815260040160405180910390fd5b8162002d90603f8262008c2d565b62002dae5760405163056e881160e01b815260040160405180910390fd5b8160000362002dd057604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038084166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162002e38906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462002e66906200a07a565b801562002eb75780601f1062002e8b5761010080835404028352916020019162002eb7565b820191906000526020600020905b81548152906001019060200180831162002e9957829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462002ee2906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462002f10906200a07a565b801562002f615780601f1062002f355761010080835404028352916020019162002f61565b820191906000526020600020905b81548152906001019060200180831162002f4357829003601f168201915b5050505050815260200160018201805462002f7c906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462002faa906200a07a565b801562002ffb5780601f1062002fcf5761010080835404028352916020019162002ffb565b820191906000526020600020905b81548152906001019060200180831162002fdd57829003601f168201915b5050505050815260200160028201805462003016906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003044906200a07a565b8015620030955780601f10620030695761010080835404028352916020019162003095565b820191906000526020600020905b8154815290600101906020018083116200307757829003601f168201915b50505050508152602001600382018054620030b0906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620030de906200a07a565b80156200312f5780601f1062003103576101008083540402835291602001916200312f565b820191906000526020600020905b8154815290600101906020018083116200311157829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620031ce575050509190925250505060408082015190516326ccee8b60e11b81526001600160a01b0385811660048301526024820188905292935060009290911690634d99dd16906044016020604051808303816000875af115801562003248573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200326e91906200a129565b9050826001600160a01b0316866001600160a01b03167f3aace7340547de7b9156593a7652dc07ee900cea3fd8f82cb6c9d38b408298028784604051620032bf929190918252602082015260400190565b60405180910390a3856001600160a01b0316836001600160a01b031603620032ec57620032ec8662008e6b565b6040808301519051633041949b60e01b815261200591633041949b9162003319919087906004016200a0b0565b600060405180830381600087803b1580156200333457600080fd5b505af115801562003349573d6000803e3d6000fd5b50505050505050505050565b60005462010000900460ff16156200338057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620033b25760405163b1d02c3d60e01b815260040160405180910390fd5b83620033c0603f8262008c2d565b620033de5760405163056e881160e01b815260040160405180910390fd5b83620033ec603f8262008c2d565b6200340a5760405163056e881160e01b815260040160405180910390fd5b6034805460ff1916600117905560008490036200343a57604051639811e0c760e01b815260040160405180910390fd5b846001600160a01b0316866001600160a01b0316036200346d5760405163f0e3e62960e01b815260040160405180910390fd5b6001600160a01b0380871660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180543394916080840191620034d5906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003503906200a07a565b8015620035545780601f10620035285761010080835404028352916020019162003554565b820191906000526020600020905b8154815290600101906020018083116200353657829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200357f906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620035ad906200a07a565b8015620035fe5780601f10620035d257610100808354040283529160200191620035fe565b820191906000526020600020905b815481529060010190602001808311620035e057829003601f168201915b5050505050815260200160018201805462003619906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003647906200a07a565b8015620036985780601f106200366c5761010080835404028352916020019162003698565b820191906000526020600020905b8154815290600101906020018083116200367a57829003601f168201915b50505050508152602001600282018054620036b3906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620036e1906200a07a565b8015620037325780601f10620037065761010080835404028352916020019162003732565b820191906000526020600020905b8154815290600101906020018083116200371457829003601f168201915b505050505081526020016003820180546200374d906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200377b906200a07a565b8015620037cc5780601f10620037a057610100808354040283529160200191620037cc565b820191906000526020600020905b815481529060010190602001808311620037ae57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200386b57505050919092525050506001600160a01b03808916600090815260416020908152604080832081516101808101835281548616815260018201548616938101939093526002810154909416908201526003830154606082015260048301805494955091939092916080840191620038f6906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003924906200a07a565b8015620039755780601f10620039495761010080835404028352916020019162003975565b820191906000526020600020905b8154815290600101906020018083116200395757829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620039a0906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620039ce906200a07a565b801562003a1f5780601f10620039f35761010080835404028352916020019162003a1f565b820191906000526020600020905b81548152906001019060200180831162003a0157829003601f168201915b5050505050815260200160018201805462003a3a906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003a68906200a07a565b801562003ab95780601f1062003a8d5761010080835404028352916020019162003ab9565b820191906000526020600020905b81548152906001019060200180831162003a9b57829003601f168201915b5050505050815260200160028201805462003ad4906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003b02906200a07a565b801562003b535780601f1062003b275761010080835404028352916020019162003b53565b820191906000526020600020905b81548152906001019060200180831162003b3557829003601f168201915b5050505050815260200160038201805462003b6e906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462003b9c906200a07a565b801562003bed5780601f1062003bc15761010080835404028352916020019162003bed565b820191906000526020600020905b81548152906001019060200180831162003bcf57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162003c8c5750505050508152505090508060e00151801562003ccf5750876001600160a01b0316836001600160a01b031614155b1562003cee57604051636468920360e01b815260040160405180910390fd5b60408083015190516352e82ce560e11b81526001600160a01b038581166004830152602482018a9052600092169063a5d059ca906044016020604051808303816000875af115801562003d45573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003d6b91906200a129565b905060375481101562003d915760405163dc6f0bdd60e01b815260040160405180910390fd5b896001600160a01b0316846001600160a01b031614801562003e2657506036546040808501519051630913db4760e01b81526001600160a01b038d8116600483015290911690630913db4790602401602060405180830381865afa15801562003dfe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003e2491906200a129565b105b1562003e45576040516317b204bf60e11b815260040160405180910390fd5b6000620186a0603a548362003e5b91906200a1c6565b62003e6791906200a0f0565b9050600083604001516001600160a01b03168260405160006040518083038185875af1925050503d806000811462003ebc576040519150601f19603f3d011682016040523d82523d6000602084013e62003ec1565b606091505b505090508062003ee4576040516312171d8360e31b815260040160405180910390fd5b62003ef082846200a1b0565b60408086015190516317066a5760e21b81526001600160a01b03898116600483015292955060009290911690635c19a95c90869060240160206040518083038185885af115801562003f46573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062003f6d91906200a129565b9050866001600160a01b03168c6001600160a01b03168e6001600160a01b03167ffdac6e81913996d95abcc289e90f2d8bd235487ce6fe6f821e7d21002a1915b48e858960405162003fd2939291909283526020830191909152604082015260600190565b60405180910390a46040805160028082526060820183526000926020830190803683370190505090508660400151816000815181106200401657620040166200a17e565b60200260200101906001600160a01b031690816001600160a01b0316815250508560400151816001815181106200405157620040516200a17e565b6001600160a01b0390921660209283029190910190910152604051634484077560e01b815261200590634484077590620040929084908c906004016200a1e0565b600060405180830381600087803b158015620040ad57600080fd5b505af1158015620040c2573d6000803e3d6000fd5b505050508a1562004134576120056001600160a01b031663e5ed5b1e898f6040518363ffffffff1660e01b8152600401620040ff9291906200a0b0565b600060405180830381600087803b1580156200411a57600080fd5b505af11580156200412f573d6000803e3d6000fd5b505050505b50506034805460ff19169055505050505050505050505050565b60005462010000900460ff16156200417957604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620041ab5760405163b1d02c3d60e01b815260040160405180910390fd5b620041b562008e2a565b620041c2603f8262008c2d565b620041e05760405163056e881160e01b815260040160405180910390fd5b6000620041ec62008e2a565b6001600160a01b0381166000908152604160205260409020600c8101549192509042906200421e90610258906200a113565b11156200423e57604051631f92cdbd60e11b815260040160405180910390fd5b60098101546001600160401b03600160401b90910481169085161115620042785760405163dc81db8560e01b815260040160405180910390fd5b60098101546000906001600160401b039081169086161015620042b6576009820154620042b09086906001600160401b03166200a20c565b620042d0565b6009820154620042d0906001600160401b0316866200a20c565b60098301546001600160401b039182169250600160801b9004168111156200430b5760405163dc81db8560e01b815260040160405180910390fd5b60098201805467ffffffffffffffff19166001600160401b03871690811790915542600c8401556040519081526001600160a01b038416907f78cdd96edf59e09cfd4d26ef6ef6c92d166effe6a40970c54821206d541932cb9060200160405180910390a25050505050565b606080606060006200438a603f62008f89565b90508086101562004a13578415620043a35784620043a5565b805b9450600085620043b688846200a1b0565b11620043ce57620043c887836200a1b0565b620043d0565b855b9050806001600160401b03811115620043ed57620043ed62009853565b60405190808252806020026020018201604052801562004417578160200160208202803683370190505b509450806001600160401b0381111562004435576200443562009853565b6040519080825280602002602001820160405280156200445f578160200160208202803683370190505b509350806001600160401b038111156200447d576200447d62009853565b604051908082528060200260200182016040528015620044b257816020015b60608152602001906001900390816200449c5790505b50925060005b8181101562004a10576000620044dc620044d3838b6200a113565b603f9062008f94565b6001600160a01b0380821660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180549495509193909291608084019162004549906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462004577906200a07a565b8015620045c85780601f106200459c57610100808354040283529160200191620045c8565b820191906000526020600020905b815481529060010190602001808311620045aa57829003601f168201915b5050505050815260200160058201604051806080016040529081600082018054620045f3906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462004621906200a07a565b8015620046725780601f10620046465761010080835404028352916020019162004672565b820191906000526020600020905b8154815290600101906020018083116200465457829003601f168201915b505050505081526020016001820180546200468d906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620046bb906200a07a565b80156200470c5780601f10620046e0576101008083540402835291602001916200470c565b820191906000526020600020905b815481529060010190602001808311620046ee57829003601f168201915b5050505050815260200160028201805462004727906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462004755906200a07a565b8015620047a65780601f106200477a57610100808354040283529160200191620047a6565b820191906000526020600020905b8154815290600101906020018083116200478857829003601f168201915b50505050508152602001600382018054620047c1906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620047ef906200a07a565b8015620048405780601f10620048145761010080835404028352916020019162004840565b820191906000526020600020905b8154815290600101906020018083116200482257829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620048df57505050505081525050905080600001518884815181106200491857620049186200a17e565b60200260200101906001600160a01b031690816001600160a01b0316815250508060e00151620049b15780604001516001600160a01b03166315d1f8986040518163ffffffff1660e01b8152600401602060405180830381865afa15801562004985573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620049ab91906200a129565b620049b4565b60005b878481518110620049c957620049c96200a17e565b6020026020010181815250508060800151868481518110620049ef57620049ef6200a17e565b602002602001018190525050508062004a08906200a194565b9050620044b8565b50505b92959194509250565b60005462010000900460ff161562004a4757604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562004a795760405163b1d02c3d60e01b815260040160405180910390fd5b3362004a87603f8262008c2d565b1562004aa657604051635f28f62b60e01b815260040160405180910390fd5b6001600160a01b038181166000908152604d6020526040902054161562004ae057604051631a0a9b9f60e21b815260040160405180910390fd5b6001600160a01b03888116600090815260436020526040902054161562004b1a57604051631e6f587560e11b815260040160405180910390fd5b60006001600160a01b03166045888860405162004b399291906200a0ca565b908152604051908190036020019020546001600160a01b03161462004b71576040516311fdb94760e01b815260040160405180910390fd5b600062004b7f83806200a236565b60405160200162004b929291906200a0ca565b60408051601f1981840301815291815281516020928301206000818152604290935291205490915060ff161562004bdc5760405163c0bf414360e01b815260040160405180910390fd5b600062004bf2670de0b6b3a7640000346200a1b0565b905060365481101562004c18576040516317b204bf60e11b815260040160405180910390fd5b6001600160a01b038a1662004c4057604051636520611b60e11b815260040160405180910390fd5b61138862004c55604087016020880162009b72565b6001600160401b0316118062004c9b575062004c78604086016020870162009b72565b6001600160401b031662004c90602087018762009b72565b6001600160401b0316115b8062004cda575062004cb4604086016020870162009b72565b6001600160401b031662004ccf606087016040880162009b72565b6001600160401b0316115b1562004cf95760405163dc81db8560e01b815260040160405180910390fd5b62004d4462004d0985806200a236565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062008fa292505050565b62004d6257604051635dba5ad760e01b815260040160405180910390fd5b62004d71838a8a8a8a62009144565b62004d8f57604051631647e3cb60e11b815260040160405180910390fd5b600062004ddd8462004da287806200a236565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200927492505050565b905062004dec603f8562009375565b506000838152604260209081526040808320805460ff191660019081179091556001600160a01b0380891680865260419094529190932080548f83166001600160a01b03199182161782559381018054851690931790925560028201805491851691909316179091554260038201556004810162004e6c8b8d836200a2de565b50856005820162004e7e82826200a3a6565b508790506009820162004e9282826200a4df565b505042600c8201556001600160a01b038c81166000908152604360205260409081902080546001600160a01b0319169288169290921790915551859060459062004ee0908e908e906200a0ca565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316856001600160a01b03168d6001600160a01b03167faecd9fb95e79c75a3a1de93362c6be5fe6ab65770d8614be583884161cd8228d8e8e60405162004f639291906200a5af565b60405180910390a460408051848152602081018590526001600160a01b0387169182917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a360408051670de0b6b3a7640000808252602082015261dead916001600160a01b038816917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e04910160405180910390a3604051633041949b60e01b815261200590633041949b906200502990859089906004016200a0b0565b600060405180830381600087803b1580156200504457600080fd5b505af115801562005059573d6000803e3d6000fd5b50505050505050505050505050505050565b60408051606081018252600080825260208201819052918101919091528162005096603f8262008c2d565b620050b45760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b031660009081526041602090815260409182902082516060810184526009909101546001600160401b038082168352600160401b8204811693830193909352600160801b90049091169181019190915290565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060828101919091526004840180549194916080840191906200517d906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620051ab906200a07a565b8015620051fc5780601f10620051d057610100808354040283529160200191620051fc565b820191906000526020600020905b815481529060010190602001808311620051de57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462005227906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005255906200a07a565b8015620052a65780601f106200527a57610100808354040283529160200191620052a6565b820191906000526020600020905b8154815290600101906020018083116200528857829003601f168201915b50505050508152602001600182018054620052c1906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620052ef906200a07a565b8015620053405780601f10620053145761010080835404028352916020019162005340565b820191906000526020600020905b8154815290600101906020018083116200532257829003601f168201915b505050505081526020016002820180546200535b906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005389906200a07a565b8015620053da5780601f10620053ae57610100808354040283529160200191620053da565b820191906000526020600020905b815481529060010190602001808311620053bc57829003601f168201915b50505050508152602001600382018054620053f5906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005423906200a07a565b8015620054745780601f10620054485761010080835404028352916020019162005474565b820191906000526020600020905b8154815290600101906020018083116200545657829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620055135750505091909252505050608001519392505050565b33611001146200556457604051630f22c43960e41b81526110016004820152602401620012e3565b6001600160a01b03808216600090815260436020526040902054166200558c603f8262008c2d565b620055aa5760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038181166000908152604160205260408082206002810154603b54925163045bc4d160e41b81526004810193909352909316906345bc4d10906024016020604051808303816000875af11580156200560d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200563391906200a129565b90506000603d54426200564791906200a113565b905062005655838262008cd8565b836001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28284600160405162005695939291906200a143565b60405180910390a26002830154604051633041949b60e01b815261200591633041949b91620056d3916001600160a01b03169088906004016200a0b0565b600060405180830381600087803b158015620056ee57600080fd5b505af115801562005703573d6000803e3d6000fd5b505050505050505050565b600054610100900460ff16158080156200572f5750600054600160ff909116105b806200574b5750303b1580156200574b575060005460ff166001145b620057b05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620012e3565b6000805460ff191660011790558015620057d4576000805461ff0019166101001790555b334114620057f55760405163022d8c9560e31b815260040160405180910390fd5b3a1562005815576040516383f1b1d360e01b815260040160405180910390fd5b611388603555686c6b935b8bbd400000603655670de0b6b3a7640000603755602d603855607860398190556002603a819055678ac7230489e80000603b55680ad78ebc5ac6200000603c55603d9190915560b4603e55604a556200588d7304d63abcd2b9b1baa327f2dda0f873f197ccd1866200938c565b80156200190e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b3361200014620058fe57604051630f22c43960e41b81526120006004820152602401620012e3565b60405162461bcd60e51b815260206004820152600a60248201526919195c1c9958d85d195960b21b6044820152606401620012e3565b600054630100000090046001600160a01b0316331462005967576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff16156200599257604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6000620059db603f8462008c2d565b620059f95760405163056e881160e01b815260040160405180910390fd5b6001600160a01b0383811660009081526041602052604090819020600201549051636bbf224960e01b815260048101859052911690636bbf2249906024015b602060405180830381865afa15801562005a56573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062005a7c91906200a129565b90505b92915050565b60005462010000900460ff161562005ab057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562005ae25760405163b1d02c3d60e01b815260040160405180910390fd5b8162005af0603f8262008c2d565b62005b0e5760405163056e881160e01b815260040160405180910390fd5b603754349081101562005b345760405163dc6f0bdd60e01b815260040160405180910390fd5b6001600160a01b038085166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054339491608084019162005b9c906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005bca906200a07a565b801562005c1b5780601f1062005bef5761010080835404028352916020019162005c1b565b820191906000526020600020905b81548152906001019060200180831162005bfd57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462005c46906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005c74906200a07a565b801562005cc55780601f1062005c995761010080835404028352916020019162005cc5565b820191906000526020600020905b81548152906001019060200180831162005ca757829003601f168201915b5050505050815260200160018201805462005ce0906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005d0e906200a07a565b801562005d5f5780601f1062005d335761010080835404028352916020019162005d5f565b820191906000526020600020905b81548152906001019060200180831162005d4157829003601f168201915b5050505050815260200160028201805462005d7a906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005da8906200a07a565b801562005df95780601f1062005dcd5761010080835404028352916020019162005df9565b820191906000526020600020905b81548152906001019060200180831162005ddb57829003601f168201915b5050505050815260200160038201805462005e14906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462005e42906200a07a565b801562005e935780601f1062005e675761010080835404028352916020019162005e93565b820191906000526020600020905b81548152906001019060200180831162005e7557829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b81548152602001906001019080831162005f325750505050508152505090508060e00151801562005f755750856001600160a01b0316826001600160a01b031614155b1562005f9457604051636468920360e01b815260040160405180910390fd5b60408082015190516317066a5760e21b81526001600160a01b0384811660048301526000921690635c19a95c90869060240160206040518083038185885af115801562005fe5573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906200600c91906200a129565b9050826001600160a01b0316876001600160a01b03167f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e0483876040516200605d929190918252602082015260400190565b60405180910390a36040808301519051633041949b60e01b815261200591633041949b9162006092919087906004016200a0b0565b600060405180830381600087803b158015620060ad57600080fd5b505af1158015620060c2573d6000803e3d6000fd5b50505050851562001907576040516372f6ad8f60e11b81526120059063e5ed5b1e90620060f69086908b906004016200a0b0565b600060405180830381600087803b1580156200611157600080fd5b505af115801562006126573d6000803e3d6000fd5b5050505050505050505050565b60005462010000900460ff16156200615e57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620061905760405163b1d02c3d60e01b815260040160405180910390fd5b6200619a62008dcc565b620061a7603f8262008c2d565b620061c55760405163056e881160e01b815260040160405180910390fd5b6000620061d162008dcc565b6001600160a01b0381166000908152604f6020526040812080549293509190859003620062a85760005b818110156200627c57836001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a8483815481106200624457620062446200a17e565b90600052602060002001546040516200625f91815260200190565b60405180910390a28062006273816200a194565b915050620061fb565b506001600160a01b0383166000908152604f60205260408120620062a0916200967e565b505050505050565b60005b8581101562006406576000878783818110620062cb57620062cb6200a17e565b90506020020135905060005b83811015620063ee5781858281548110620062f657620062f66200a17e565b906000526020600020015403620063d95784620063156001866200a1b0565b815481106200632857620063286200a17e565b90600052602060002001548582815481106200634857620063486200a17e565b9060005260206000200181905550848054806200636957620063696200a5c5565b6001900381819060005260206000200160009055905583806200638c906200a5db565b945050856001600160a01b03167f08e60c1b84aab23d99a7262015e647d5ffd6c6e08f78205e1df6774c48e1427a83604051620063cb91815260200190565b60405180910390a2620063ee565b80620063e5816200a194565b915050620062d7565b50508080620063fd906200a194565b915050620062ab565b508154600003620062a0576001600160a01b0383166000908152604f60205260408120620062a0916200967e565b505050565b620064656040518060800160405280606081526020016060815260200160608152602001606081525090565b8162006473603f8262008c2d565b620064915760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03831660009081526041602052604090819020815160808101909252600501805482908290620064c8906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620064f6906200a07a565b8015620065475780601f106200651b5761010080835404028352916020019162006547565b820191906000526020600020905b8154815290600101906020018083116200652957829003601f168201915b5050505050815260200160018201805462006562906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462006590906200a07a565b8015620065e15780601f10620065b557610100808354040283529160200191620065e1565b820191906000526020600020905b815481529060010190602001808311620065c357829003601f168201915b50505050508152602001600282018054620065fc906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200662a906200a07a565b80156200667b5780601f106200664f576101008083540402835291602001916200667b565b820191906000526020600020905b8154815290600101906020018083116200665d57829003601f168201915b5050505050815260200160038201805462006696906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620066c4906200a07a565b8015620067155780601f10620066e95761010080835404028352916020019162006715565b820191906000526020600020905b815481529060010190602001808311620066f757829003601f168201915b505050505081525050915050919050565b60005462010000900460ff16156200675157604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620067835760405163b1d02c3d60e01b815260040160405180910390fd5b6200678f828262009425565b5050565b3361100714620067bb57604051630f22c43960e41b81526110076004820152602401620012e3565b620068286040518060400160405280601081526020016f1d1c985b9cd9995c91d85cd31a5b5a5d60821b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b15620068e357602081146200685a5783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f84018190048102820181019092528281526000916200689d9185858083850183828082843760009201919091525092939250506200958e9050565b90506108fc811080620068b1575061271081115b15620068da5784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b60355562007700565b620069546040518060400160405280601481526020017336b4b729b2b6332232b632b3b0ba34b7b721272160611b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b1562006a1e5760208114620069865783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f8401819004810282018101909252828152600091620069c99185858083850183828082843760009201919091525092939250506200958e9050565b9050683635c9adc5dea00000811080620069ec575069152d02c7e14af680000081115b1562006a155784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b60365562007700565b62006a91604051806040016040528060168152602001756d696e44656c65676174696f6e424e424368616e676560501b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b1562006b58576020811462006ac35783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f840181900481028201810190925282815260009162006b069185858083850183828082843760009201919091525092939250506200958e9050565b905067016345785d8a000081108062006b265750678ac7230489e8000081115b1562006b4f5784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b60375562007700565b62006bc9604051806040016040528060148152602001736d6178456c656374656456616c696461746f727360601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b1562006c81576020811462006bfb5783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f840181900481028201810190925282815260009162006c3e9185858083850183828082843760009201919091525092939250506200958e9050565b905080158062006c4f57506101f481115b1562006c785784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b60385562007700565b62006cea6040518060400160405280600c81526020016b1d5b989bdb9914195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b1562006da7576020811462006d1c5783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f840181900481028201810190925282815260009162006d5f9185858083850183828082843760009201919091525092939250506200958e9050565b90506203f48081108062006d75575062278d0081115b1562006d9e5784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b60395562007700565b62006e1560405180604001604052806011815260200170726564656c65676174654665655261746560781b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b1562006ec2576020811462006e475783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f840181900481028201810190925282815260009162006e8a9185858083850183828082843760009201919091525092939250506200958e9050565b9050606481111562006eb95784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b603a5562007700565b62006f3260405180604001604052806013815260200172191bdddb9d1a5b5954db185cda105b5bdd5b9d606a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b1562006ff4576020811462006f645783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f840181900481028201810190925282815260009162006fa79185858083850183828082843760009201919091525092939250506200958e9050565b9050670de0b6b3a764000081108062006fc25750603c548110155b1562006feb5784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b603b5562007700565b620070626040518060400160405280601181526020017019995b1bdb9e54db185cda105b5bdd5b9d607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b15620071245760208114620070945783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f8401819004810282018101909252828152600091620070d79185858083850183828082843760009201919091525092939250506200958e9050565b9050678ac7230489e80000811080620070f25750603b548111155b156200711b5784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b603c5562007700565b620071916040518060400160405280601081526020016f646f776e74696d654a61696c54696d6560801b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b156200724e5760208114620071c35783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f8401819004810282018101909252828152600091620072069185858083850183828082843760009201919091525092939250506200958e9050565b9050620151808110806200721c5750603e548110155b15620072455784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b603d5562007700565b620072b96040518060400160405280600e81526020016d66656c6f6e794a61696c54696d6560901b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b15620073765760208114620072eb5783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f84018190048102820181019092528281526000916200732e9185858083850183828082843760009201919091525092939250506200958e9050565b90506203f480811080620073445750603d548111155b156200736d5784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b603e5562007700565b620073f06040518060400160405280601c81526020017f6d617846656c6f6e794265747765656e42726561746865426c6f636b0000000081525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b156200749c5760208114620074225783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f8401819004810282018101909252828152600091620074659185858083850183828082843760009201919091525092939250506200958e9050565b905080600003620074935784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604a5562007700565b6200750a6040518060400160405280601181526020017039ba30b5b2a43ab1283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b15620075ca57601481146200753c5783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b600062007584601484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506200958e9050565b90506001600160a01b038116620075b85784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b620075c38162009593565b5062007700565b620076316040518060400160405280600a8152602001696d61784e6f646549447360b01b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050620095319050565b15620076dd5760208114620076635783838383604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604080516020601f8401819004810282018101909252828152600091620076a69185858083850183828082843760009201919091525092939250506200958e9050565b905080600003620076d45784848484604051630a5a604160e01b8152600401620012e394939291906200a5f5565b604e5562007700565b838383836040516325ee20d560e21b8152600401620012e394939291906200a5f5565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516200773794939291906200a5f5565b60405180910390a150505050565b60005462010000900460ff16156200777057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620077a25760405163b1d02c3d60e01b815260040160405180910390fd5b816000816001600160401b03811115620077c057620077c062009853565b604051908082528060200260200182016040528015620077ea578160200160208202803683370190505b5090506000805b83811015620078e857620078338787838181106200781357620078136200a17e565b90506020020160208101906200782a9190620096e4565b603f9062008c2d565b620078515760405163056e881160e01b815260040160405180910390fd5b604160008888848181106200786a576200786a6200a17e565b9050602002016020810190620078819190620096e4565b6001600160a01b0390811682526020820192909252604001600020600201548451911692508290849083908110620078bd57620078bd6200a17e565b6001600160a01b0390921660209283029190910190910152620078e0816200a194565b9050620077f1565b50604051634484077560e01b8152612005906344840775906200331990859088906004016200a1e0565b606080600062007923603f62008f89565b90508085101562007ae75783156200793c57836200793e565b805b93506000846200794f87846200a1b0565b1162007967576200796186836200a1b0565b62007969565b845b9050806001600160401b0381111562007986576200798662009853565b604051908082528060200260200182016040528015620079b0578160200160208202803683370190505b509350806001600160401b03811115620079ce57620079ce62009853565b604051908082528060200260200182016040528015620079f8578160200160208202803683370190505b50925060005b8181101562007ae45762007a17620044d382896200a113565b85828151811062007a2c5762007a2c6200a17e565b60200260200101906001600160a01b031690816001600160a01b0316815250506041600086838151811062007a655762007a656200a17e565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060020160009054906101000a90046001600160a01b031684828151811062007ab95762007ab96200a17e565b6001600160a01b039092166020928302919091019091015262007adc816200a194565b9050620079fe565b50505b9250925092565b60008162007afe603f8262008c2d565b62007b1c5760405163056e881160e01b815260040160405180910390fd5b50506001600160a01b03166000908152604160205260409020600c015490565b336110011462007b6457604051630f22c43960e41b81526110016004820152602401620012e3565b60005462010000900460ff161562007b8f57604051631785c68160e01b815260040160405180910390fd5b6001600160a01b038082166000908152604360205260409020541662007bb7603f8262008c2d565b62007bd55760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03811660009081526041602052604081209062007bfc610258426200a0f0565b604a546000828152604b60205260409020549192501162007c305760405163bd52fcdb60e01b815260040160405180910390fd5b6000818152604b6020526040812080546001929062007c519084906200a113565b90915550506001600160a01b0384166000908152604460205260409020541580159062007ca557506001600160a01b038416600090815260446020526040902054429062007ca390610258906200a113565b105b1562007cc4576040516330abb81d60e21b815260040160405180910390fd5b60008062007cd485600062008c50565b915091508162007cf757604051631b919bb160e11b815260040160405180910390fd5b6002840154603c5460405163045bc4d160e41b815260048101919091526000916001600160a01b0316906345bc4d10906024016020604051808303816000875af115801562007d4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062007d7091906200a129565b905062007d7e858362008cd8565b856001600160a01b03167f6e9a2ee7aee95665e3a774a212eb11441b217e3e4656ab9563793094689aabb28383600060405162007dbe939291906200a143565b60405180910390a26002850154604051633041949b60e01b815261200591633041949b91620060f6916001600160a01b0316908a906004016200a0b0565b6001600160a01b038082166000908152604160209081526040808320815161018081018352815486168152600182015486169381019390935260028101549094169082015260038301546060820152600483018054929384938493849390929160808401919062007e6d906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462007e9b906200a07a565b801562007eec5780601f1062007ec05761010080835404028352916020019162007eec565b820191906000526020600020905b81548152906001019060200180831162007ece57829003601f168201915b505050505081526020016005820160405180608001604052908160008201805462007f17906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462007f45906200a07a565b801562007f965780601f1062007f6a5761010080835404028352916020019162007f96565b820191906000526020600020905b81548152906001019060200180831162007f7857829003601f168201915b5050505050815260200160018201805462007fb1906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462007fdf906200a07a565b8015620080305780601f10620080045761010080835404028352916020019162008030565b820191906000526020600020905b8154815290600101906020018083116200801257829003601f168201915b505050505081526020016002820180546200804b906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462008079906200a07a565b8015620080ca5780601f106200809e57610100808354040283529160200191620080ca565b820191906000526020600020905b815481529060010190602001808311620080ac57829003601f168201915b50505050508152602001600382018054620080e5906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462008113906200a07a565b8015620081645780601f10620081385761010080835404028352916020019162008164565b820191906000526020600020905b8154815290600101906020018083116200814657829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b815481526020019060010190808311620082035750505091909252505050606081015160e0820151610100909201519097919650945092505050565b60005462010000900460ff16156200826a57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156200829c5760405163b1d02c3d60e01b815260040160405180910390fd5b620082a662008e2a565b620082b3603f8262008c2d565b620082d15760405163056e881160e01b815260040160405180910390fd5b6000620082dd62008e2a565b6001600160a01b0381166000908152604160205260409020600c8101549192509042906200830f90610258906200a113565b11156200832f57604051631f92cdbd60e11b815260040160405180910390fd5b60058101805462008340906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200836e906200a07a565b8015620083bf5780601f106200839357610100808354040283529160200191620083bf565b820191906000526020600020905b815481529060010190602001808311620083a157829003601f168201915b5050508287525085916005840191508190620083dc90826200a62b565b5060208201516001820190620083f390826200a62b565b50604082015160028201906200840a90826200a62b565b50606082015160038201906200842190826200a62b565b505042600c830155506040516001600160a01b038316907f85d6366b336ade7f106987ec7a8eac1e8799e508aeab045a39d2f63e0dc969d990600090a250505050565b60005462010000900460ff16156200848f57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615620084c15760405163b1d02c3d60e01b815260040160405180910390fd5b828114620084e2576040516341abc80160e01b815260040160405180910390fd5b60005b838110156200855357620085408585838181106200850757620085076200a17e565b90506020020160208101906200851e9190620096e4565b8484848181106200853357620085336200a17e565b9050602002013562009425565b6200854b816200a194565b9050620084e5565b5050505050565b6001600160a01b0380821660009081526041602090815260408083208151610180810183528154861681526001820154861693810193909352600281015490941690820152600383015460608201526004830180549293849390916080840191620085c5906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620085f3906200a07a565b8015620086445780601f10620086185761010080835404028352916020019162008644565b820191906000526020600020905b8154815290600101906020018083116200862657829003601f168201915b50505050508152602001600582016040518060800160405290816000820180546200866f906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200869d906200a07a565b8015620086ee5780601f10620086c257610100808354040283529160200191620086ee565b820191906000526020600020905b815481529060010190602001808311620086d057829003601f168201915b5050505050815260200160018201805462008709906200a07a565b80601f016020809104026020016040519081016040528092919081815260200182805462008737906200a07a565b8015620087885780601f106200875c5761010080835404028352916020019162008788565b820191906000526020600020905b8154815290600101906020018083116200876a57829003601f168201915b50505050508152602001600282018054620087a3906200a07a565b80601f0160208091040260200160405190810160405280929190818152602001828054620087d1906200a07a565b8015620088225780601f10620087f65761010080835404028352916020019162008822565b820191906000526020600020905b8154815290600101906020018083116200880457829003601f168201915b505050505081526020016003820180546200883d906200a07a565b80601f01602080910402602001604051908101604052809291908181526020018280546200886b906200a07a565b8015620088bc5780601f106200889057610100808354040283529160200191620088bc565b820191906000526020600020905b8154815290600101906020018083116200889e57829003601f168201915b505050919092525050508152604080516060808201835260098501546001600160401b038082168452600160401b82048116602080860191909152600160801b9092041683850152840191909152600a84015460ff16151582840152600b84015490830152600c8301546080830152600d8301546001600160a01b031660a0830152805161026081019182905260c09092019190600e84019060139082845b8154815260200190600101908083116200895b5750505091909252505050604001519392505050565b600062008993603f8462008c2d565b620089b15760405163056e881160e01b815260040160405180910390fd5b6001600160a01b038381166000908152604160205260409081902060020154905163aa1966cd60e01b81526004810185905291169063aa1966cd9060240162005a38565b60005462010000900460ff161562008a2057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161562008a525760405163b1d02c3d60e01b815260040160405180910390fd5b62008a5c62008e2a565b62008a69603f8262008c2d565b62008a875760405163056e881160e01b815260040160405180910390fd5b600062008a9362008e2a565b905062008aa4818787878762009144565b62008ac257604051631647e3cb60e11b815260040160405180910390fd5b60006001600160a01b03166045878760405162008ae19291906200a0ca565b908152604051908190036020019020546001600160a01b03161462008b19576040516311fdb94760e01b815260040160405180910390fd5b6001600160a01b0381166000908152604160205260409020600c810154429062008b4790610258906200a113565b111562008b6757604051631f92cdbd60e11b815260040160405180910390fd5b4260468260040160405162008b7d91906200a6f3565b908152604051908190036020019020556004810162008b9e8789836200a2de565b5042600c820155604051829060459062008bbc908a908a906200a0ca565b90815260405190819003602001812080546001600160a01b039384166001600160a01b0319909116179055908316907f783156582145bd0ff7924fae6953ba054cf1233eb60739a200ddb10de068ff0d9062008c1c908a908a906200a5af565b60405180910390a250505050505050565b6001600160a01b0381166000908152600183016020526040812054151562005a7c565b6000806000848460405160200162008c6a9291906200a771565b60408051601f1981840301815291815281516020928301206000818152604c9093529120549091504281111562008caa5760008093509350505062002647565b603e5462008cb990426200a113565b6000928352604c60205260409092208290555060019590945092505050565b6000600162008ce8603f62008f89565b62008cf491906200a1b0565b604954108015915062008d405760018301546040516001600160a01b03909116907f2afdc18061ac21cff7d9f11527ab9c8dec6fabd4edf6f894ed634bebd6a20d4590600090a2505050565b82600b015482111562008d5557600b83018290555b600a83015460ff166200643457600a8301805460ff191660019081179091556049805460009062008d889084906200a113565b909155505060018301546040516001600160a01b03909116907f4905ac32602da3fb8b4b7b00c285e5fc4c6c2308cc908b4a1e4e9625a29c90a390600090a2505050565b336000908152604360205260408120546001600160a01b03161562008e085750336000908152604360205260409020546001600160a01b031690565b62008e1262008e2a565b905090565b604e5460000362008e28576005604e555b565b336000908152604d60205260408120546001600160a01b03161562008e665750336000908152604d60205260409020546001600160a01b031690565b503390565b6001600160a01b0381166000908152604160205260409020600a81015460ff161562008e95575050565b6036546002820154604051630913db4760e01b81526001600160a01b03858116600483015290911690630913db4790602401602060405180830381865afa15801562008ee5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062008f0b91906200a129565b10156200678f5762008f2d81603d544262008f2791906200a113565b62008cd8565b80546040516335409f7f60e01b81526001600160a01b039091166004820152611000906335409f7f90602401600060405180830381600087803b15801562008f7457600080fd5b505af1158015620062a0573d6000803e3d6000fd5b600062005a7f825490565b600062005a7c8383620095ff565b60008082905060038151108062008fba575060098151115b1562008fc95750600092915050565b60418160008151811062008fe15762008fe16200a17e565b016020015160f81c1080620090135750605a816000815181106200900957620090096200a17e565b016020015160f81c115b15620090225750600092915050565b60015b81518110156200913a5760308282815181106200904657620090466200a17e565b016020015160f81c108062009077575060398282815181106200906d576200906d6200a17e565b016020015160f81c115b8015620090c7575060418282815181106200909657620090966200a17e565b016020015160f81c1080620090c75750605a828281518110620090bd57620090bd6200a17e565b016020015160f81c115b80156200911757506061828281518110620090e657620090e66200a17e565b016020015160f81c1080620091175750607a8282815181106200910d576200910d6200a17e565b016020015160f81c115b1562009127575060009392505050565b62009132816200a194565b905062009025565b5060019392505050565b600060308414158062009158575060608214155b1562009167575060006200926b565b6000868686466040516020016200918294939291906200a7bb565b60408051808303601f1901815282825280516020918201208184528383019092529092506000919060208201818036833701905050905081602082015260008186868a8a604051602001620091dc9594939291906200a7e8565b60408051808303601f190181526001808452838301909252925060009190602082018180368337019050509050815160016020830182602086016066600019fa6200922657600080fd5b506000816000815181106200923f576200923f6200a17e565b016020015160f81c90506001811462009261576000955050505050506200926b565b6001955050505050505b95945050505050565b60008061200361dead6040516200928b906200969e565b6001600160a01b03928316815291166020820152606060408201819052600090820152608001604051809103906000f080158015620092ce573d6000803e3d6000fd5b509050806001600160a01b031663f399e22e3486866040518463ffffffff1660e01b8152600401620093029291906200a820565b6000604051808303818588803b1580156200931c57600080fd5b505af115801562009331573d6000803e3d6000fd5b50506040516001600160a01b038086169450881692507fd481492e4e93bb36b4c12a5af93f03be3bf04b454dfbc35dd2663fa26f44d5b09150600090a39392505050565b600062005a7c836001600160a01b0384166200962c565b600054610100900460ff16620093f95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401620012e3565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b8162009433603f8262008c2d565b620094515760405163056e881160e01b815260040160405180910390fd5b6001600160a01b03838116600090815260416020526040808220600201549051635569f64b60e11b8152336004820152602481018690529192169063aad3ec96906044016020604051808303816000875af1158015620094b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620094db91906200a129565b9050336001600160a01b0316846001600160a01b03167ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd3992683836040516200952391815260200190565b60405180910390a350505050565b6000816040516020016200954691906200a846565b60405160208183030381529060405280519060200120836040516020016200956f91906200a846565b6040516020818303038152906040528051906020012014905092915050565b015190565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008260000182815481106200961957620096196200a17e565b9060005260206000200154905092915050565b6000818152600183016020526040812054620096755750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562005a7f565b50600062005a7f565b50805460008255906000526020600020908101906200190e9190620096ac565b610e96806200a86583390190565b5b80821115620096c35760008155600101620096ad565b5090565b80356001600160a01b0381168114620096df57600080fd5b919050565b600060208284031215620096f757600080fd5b62005a7c82620096c7565b60008083601f8401126200971557600080fd5b5081356001600160401b038111156200972d57600080fd5b6020830191508360208285010111156200264757600080fd5b600080602083850312156200975a57600080fd5b82356001600160401b038111156200977157600080fd5b6200977f8582860162009702565b90969095509350505050565b600080600060408486031215620097a157600080fd5b833560ff81168114620097b357600080fd5b925060208401356001600160401b03811115620097cf57600080fd5b620097dd8682870162009702565b9497909650939450505050565b60005b8381101562009807578181015183820152602001620097ed565b50506000910152565b600081518084526200982a816020860160208601620097ea565b601f01601f19169290920160200192915050565b60208152600062005a7c602083018462009810565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156200988e576200988e62009853565b60405290565b60006001600160401b0380841115620098b157620098b162009853565b604051601f8501601f19908116603f01168101908282118183101715620098dc57620098dc62009853565b81604052809350858152868686011115620098f657600080fd5b858560208301376000602087830101525050509392505050565b6000602082840312156200992357600080fd5b81356001600160401b038111156200993a57600080fd5b8201601f810184136200994c57600080fd5b6200995d8482356020840162009894565b949350505050565b60008083601f8401126200997857600080fd5b5081356001600160401b038111156200999057600080fd5b6020830191508360208260051b85010111156200264757600080fd5b60008060208385031215620099c057600080fd5b82356001600160401b03811115620099d757600080fd5b6200977f8582860162009965565b600081518084526020808501945080840160005b8381101562009a205781516001600160a01b031687529582019590820190600101620099f9565b509495945050505050565b60408152600062009a406040830185620099e5565b6020838203818501528185518084528284019150828160051b8501018388016000805b8481101562009aba57878403601f19018652825180518086529088019088860190845b8181101562009aa45783518352928a0192918a019160010162009a86565b5050968801969450509186019160010162009a63565b50919a9950505050505050505050565b6000806040838503121562009ade57600080fd5b62009ae983620096c7565b946020939093013593505050565b80358015158114620096df57600080fd5b6000806000806080858703121562009b1f57600080fd5b62009b2a85620096c7565b935062009b3a60208601620096c7565b92506040850135915062009b516060860162009af7565b905092959194509250565b6001600160401b03811681146200190e57600080fd5b60006020828403121562009b8557600080fd5b813562009b928162009b5c565b9392505050565b6000806040838503121562009bad57600080fd5b50508035926020909101359150565b60808152600062009bd16080830187620099e5565b82810360208481019190915286518083528782019282019060005b8181101562009c0a5784518352938301939183019160010162009bec565b5050848103604086015286518082528282019350600581901b8201830183890160005b8381101562009c5f57601f1985840301875262009c4c83835162009810565b9686019692509085019060010162009c2d565b5050809550505050505082606083015295945050505050565b600080600080600080600087890360e081121562009c9557600080fd5b62009ca089620096c7565b975060208901356001600160401b038082111562009cbd57600080fd5b62009ccb8c838d0162009702565b909950975060408b013591508082111562009ce557600080fd5b62009cf38c838d0162009702565b90975095508591506060605f198401121562009d0e57600080fd5b60608b01945060c08b013592508083111562009d2957600080fd5b505088016080818b03121562009d3e57600080fd5b8091505092959891949750929550565b6000806040838503121562009d6257600080fd5b62009d6d83620096c7565b915062009d7d6020840162009af7565b90509250929050565b60208152600082516080602084015262009da460a084018262009810565b90506020840151601f198085840301604086015262009dc4838362009810565b9250604086015191508085840301606086015262009de3838362009810565b92506060860151915080858403016080860152506200926b828262009810565b6000806000806040858703121562009e1a57600080fd5b84356001600160401b038082111562009e3257600080fd5b62009e408883890162009702565b9096509450602087013591508082111562009e5a57600080fd5b5062009e698782880162009702565b95989497509550505050565b60008060006040848603121562009e8b57600080fd5b83356001600160401b0381111562009ea257600080fd5b62009eb08682870162009965565b909450925062009ec5905060208501620096c7565b90509250925092565b60608152600062009ee36060830186620099e5565b828103602084015262009ef78186620099e5565b915050826040830152949350505050565b600082601f83011262009f1a57600080fd5b62005a7c8383356020850162009894565b60006020828403121562009f3e57600080fd5b81356001600160401b038082111562009f5657600080fd5b908301906080828603121562009f6b57600080fd5b62009f7562009869565b82358281111562009f8557600080fd5b62009f938782860162009f08565b82525060208301358281111562009fa957600080fd5b62009fb78782860162009f08565b60208301525060408301358281111562009fd057600080fd5b62009fde8782860162009f08565b60408301525060608301358281111562009ff757600080fd5b6200a0058782860162009f08565b60608301525095945050505050565b600080600080604085870312156200a02b57600080fd5b84356001600160401b03808211156200a04357600080fd5b6200a0518883890162009965565b909650945060208701359150808211156200a06b57600080fd5b5062009e698782880162009965565b600181811c908216806200a08f57607f821691505b6020821081036200207957634e487b7160e01b600052602260045260246000fd5b6001600160a01b0392831681529116602082015260400190565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b6000826200a10e57634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111562005a7f5762005a7f6200a0da565b6000602082840312156200a13c57600080fd5b5051919050565b8381526020810183905260608101600383106200a17057634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200a1a9576200a1a96200a0da565b5060010190565b8181038181111562005a7f5762005a7f6200a0da565b808202811582820484141762005a7f5762005a7f6200a0da565b6040815260006200a1f56040830185620099e5565b905060018060a01b03831660208301529392505050565b6001600160401b038281168282160390808211156200a22f576200a22f6200a0da565b5092915050565b6000808335601e198436030181126200a24e57600080fd5b8301803591506001600160401b038211156200a26957600080fd5b6020019150368190038213156200264757600080fd5b601f8211156200643457600081815260208120601f850160051c810160208610156200a2a85750805b601f850160051c820191505b81811015620062a0578281556001016200a2b4565b600019600383901b1c191660019190911b1790565b6001600160401b038311156200a2f8576200a2f862009853565b6200a310836200a30983546200a07a565b836200a27f565b6000601f8411600181146200a34357600085156200a32e5750838201355b6200a33a86826200a2c9565b84555062008553565b600083815260209020601f19861690835b828110156200a37657868501358255602094850194600190920191016200a354565b50868210156200a3945760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6200a3b282836200a236565b6001600160401b038111156200a3cc576200a3cc62009853565b6200a3e4816200a3dd85546200a07a565b856200a27f565b6000601f8211600181146200a41757600083156200a4025750838201355b6200a40e84826200a2c9565b8655506200a474565b600085815260209020601f19841690835b828110156200a44a57868501358255602094850194600190920191016200a428565b50848210156200a4685760001960f88660031b161c19848701351681555b505060018360011b0185555b505050506200a48760208301836200a236565b6200a4978183600186016200a2de565b50506200a4a860408301836200a236565b6200a4b88183600286016200a2de565b50506200a4c960608301836200a236565b6200a4d98183600386016200a2de565b50505050565b81356200a4ec8162009b5c565b6001600160401b03811690508154816001600160401b0319821617835560208401356200a5198162009b5c565b6fffffffffffffffff0000000000000000604091821b166fffffffffffffffffffffffffffffffff198316841781178555908501356200a5598162009b5c565b6001600160c01b0319929092169092179190911760809190911b67ffffffffffffffff60801b1617905550565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260006200995d6020830184866200a586565b634e487b7160e01b600052603160045260246000fd5b6000816200a5ed576200a5ed6200a0da565b506000190190565b6040815260006200a60b6040830186886200a586565b82810360208401526200a6208185876200a586565b979650505050505050565b81516001600160401b038111156200a647576200a64762009853565b6200a65f816200a65884546200a07a565b846200a27f565b602080601f8311600181146200a69357600084156200a67e5750858301515b6200a68a85826200a2c9565b865550620062a0565b600085815260208120601f198616915b828110156200a6c4578886015182559484019460019091019084016200a6a3565b50858210156200a6e35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200a703816200a07a565b600182811680156200a71e57600181146200a734576200a765565b60ff19841687528215158302870194506200a765565b8760005260208060002060005b858110156200a75c5781548a8201529084019082016200a741565b50505082870194505b50929695505050505050565b6bffffffffffffffffffffffff198360601b1681526000600383106200a7a757634e487b7160e01b600052602160045260246000fd5b5060f89190911b6014820152601501919050565b6bffffffffffffffffffffffff198560601b16815282846014830137601492019182015260340192915050565b600086516200a7fc818460208b01620097ea565b82018587823760009086019081528385823760009301928352509095945050505050565b6001600160a01b03831681526040602082018190526000906200995d9083018462009810565b600082516200a85a818460208701620097ea565b919091019291505056fe608060405260405162000e9638038062000e96833981016040819052620000269162000497565b828162000036828260006200004d565b50620000449050826200008a565b505050620005ca565b6200005883620000e5565b600082511180620000665750805b1562000085576200008383836200012760201b620001691760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000b562000156565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e2816200018f565b50565b620000f08162000244565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200014f838360405180606001604052806027815260200162000e6f60279139620002f8565b9392505050565b60006200018060008051602062000e4f83398151915260001b6200037760201b620001951760201c565b546001600160a01b0316919050565b6001600160a01b038116620001fa5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200022360008051602062000e4f83398151915260001b6200037760201b620001951760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200025a816200037a60201b620001981760201c565b620002be5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f1565b80620002237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037760201b620001951760201c565b6060600080856001600160a01b03168560405162000317919062000577565b600060405180830381855af49150503d806000811462000354576040519150601f19603f3d011682016040523d82523d6000602084013e62000359565b606091505b5090925090506200036d8683838762000389565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620003fd578251600003620003f5576001600160a01b0385163b620003f55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f1565b508162000409565b62000409838362000411565b949350505050565b815115620004225781518083602001fd5b8060405162461bcd60e51b8152600401620001f1919062000595565b80516001600160a01b03811681146200045657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200048e57818101518382015260200162000474565b50506000910152565b600080600060608486031215620004ad57600080fd5b620004b8846200043e565b9250620004c8602085016200043e565b60408501519092506001600160401b0380821115620004e657600080fd5b818601915086601f830112620004fb57600080fd5b8151818111156200051057620005106200045b565b604051601f8201601f19908116603f011681019083821181831017156200053b576200053b6200045b565b816040528281528960208487010111156200055557600080fd5b6200056883602083016020880162000471565b80955050505050509250925092565b600082516200058b81846020870162000471565b9190910192915050565b6020815260008251806020840152620005b681604085016020870162000471565b601f01601f19169190910160400192915050565b61087580620005da6000396000f3fe60806040523661001357610011610017565b005b6100115b61001f6101a7565b6001600160a01b0316330361015f5760606001600160e01b0319600035166364d3180d60e11b810161005a576100536101da565b9150610157565b63587086bd60e11b6001600160e01b031982160161007a57610053610231565b63070d7c6960e41b6001600160e01b031982160161009a57610053610277565b621eb96f60e61b6001600160e01b03198216016100b9576100536102a8565b63a39f25e560e01b6001600160e01b03198216016100d9576100536102e8565b60405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b815160208301f35b6101676102fc565b565b606061018e83836040518060600160405280602781526020016108426027913961030c565b9392505050565b90565b6001600160a01b03163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b60606101e4610384565b60006101f33660048184610695565b81019061020091906106db565b905061021d8160405180602001604052806000815250600061038f565b505060408051602081019091526000815290565b60606000806102433660048184610695565b810190610250919061070c565b915091506102608282600161038f565b604051806020016040528060008152509250505090565b6060610281610384565b60006102903660048184610695565b81019061029d91906106db565b905061021d816103bb565b60606102b2610384565b60006102bc6101a7565b604080516001600160a01b03831660208201529192500160405160208183030381529060405291505090565b60606102f2610384565b60006102bc610412565b610167610307610412565b610421565b6060600080856001600160a01b03168560405161032991906107f2565b600060405180830381855af49150503d8060008114610364576040519150601f19603f3d011682016040523d82523d6000602084013e610369565b606091505b509150915061037a86838387610445565b9695505050505050565b341561016757600080fd5b610398836104c6565b6000825111806103a55750805b156103b6576103b48383610169565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103e46101a7565b604080516001600160a01b03928316815291841660208301520160405180910390a161040f81610506565b50565b600061041c6105af565b905090565b3660008037600080366000845af43d6000803e808015610440573d6000f35b3d6000fd5b606083156104b45782516000036104ad576001600160a01b0385163b6104ad5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161014e565b50816104be565b6104be83836105d7565b949350505050565b6104cf81610601565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b03811661056b5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b606482015260840161014e565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6101cb565b8151156105e75781518083602001fd5b8060405162461bcd60e51b815260040161014e919061080e565b6001600160a01b0381163b61066e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161014e565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61058e565b600080858511156106a557600080fd5b838611156106b257600080fd5b5050820193919092039150565b80356001600160a01b03811681146106d657600080fd5b919050565b6000602082840312156106ed57600080fd5b61018e826106bf565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561071f57600080fd5b610728836106bf565b9150602083013567ffffffffffffffff8082111561074557600080fd5b818501915085601f83011261075957600080fd5b81358181111561076b5761076b6106f6565b604051601f8201601f19908116603f01168101908382118183101715610793576107936106f6565b816040528281528860208487010111156107ac57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60005b838110156107e95781810151838201526020016107d1565b50506000910152565b600082516108048184602087016107ce565b9190910192915050565b602081526000825180602084015261082d8160408501602087016107ce565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000811000a" + }, + "0x0000000000000000000000000000000000002003": { + "balance": "0x0", + "code": "0x6080604052600436106101d15760003560e01c8063647df759116100f7578063a9059cbb11610095578063c2cde2b211610064578063c2cde2b21461063c578063d241c1ea1461065c578063dd62ed3e1461069e578063f399e22e146106be57600080fd5b8063a9059cbb146105af578063a9664feb146105cf578063aa1966cd146105ef578063aad3ec961461061c57600080fd5b806391faf0b4116100d157806391faf0b41461053a57806395d89b411461055a578063a457c2d71461056f578063a5d059ca1461058f57600080fd5b8063647df759146104b75780636bbf2249146104d757806370a082311461050457600080fd5b80632f2d448a1161016f57806345bc4d101161013e57806345bc4d101461044f5780634d99dd161461046f5780635c19a95c1461048f5780635e607d76146104a257600080fd5b80632f2d448a146103bb578063313ce567146103db57806339509351146103f75780633a5381b51461041757600080fd5b8063095ea7b3116101ab578063095ea7b31461034057806315d1f8981461037057806318160ddd1461038657806323b872dd1461039b57600080fd5b8063038c0023146102cb57806306fdde03146102fe5780630913db471461032057600080fd5b366102c657336120021461020157604051630f22c43960e41b815261200260048201526024015b60405180910390fd5b60006120026001600160a01b0316631fa8882b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610243573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102679190611d9e565b6102719042611dcd565b6098546000828152609d6020908152604080832093909355609c9052908120805492935034929091906102a5908490611def565b9250508190555034609860008282546102be9190611def565b925050819055005b600080fd5b3480156102d757600080fd5b506102eb6102e6366004611e1a565b6106d1565b6040519081526020015b60405180910390f35b34801561030a57600080fd5b50610313610701565b6040516102f59190611e3e565b34801561032c57600080fd5b506102eb61033b366004611e1a565b610793565b34801561034c57600080fd5b5061036061035b366004611e8c565b6107b5565b60405190151581526020016102f5565b34801561037c57600080fd5b506102eb60985481565b34801561039257600080fd5b506067546102eb565b3480156103a757600080fd5b506103606103b6366004611eb8565b6107cd565b3480156103c757600080fd5b506102eb6103d6366004611e1a565b6107f1565b3480156103e757600080fd5b50604051601281526020016102f5565b34801561040357600080fd5b50610360610412366004611e8c565b6108b6565b34801561042357600080fd5b50609754610437906001600160a01b031681565b6040516001600160a01b0390911681526020016102f5565b34801561045b57600080fd5b506102eb61046a366004611ef9565b6108d8565b34801561047b57600080fd5b506102eb61048a366004611e8c565b6109cb565b6102eb61049d366004611e1a565b610be2565b6104b56104b0366004611f12565b610c58565b005b3480156104c357600080fd5b506102eb6104d2366004611ef9565b610dcb565b3480156104e357600080fd5b506102eb6104f2366004611ef9565b609d6020526000908152604090205481565b34801561051057600080fd5b506102eb61051f366004611e1a565b6001600160a01b031660009081526065602052604090205490565b34801561054657600080fd5b506102eb610555366004611ef9565b610e0a565b34801561056657600080fd5b50610313610e45565b34801561057b57600080fd5b5061036061058a366004611e8c565b610e54565b34801561059b57600080fd5b506102eb6105aa366004611e8c565b610ecf565b3480156105bb57600080fd5b506103606105ca366004611e8c565b610fd0565b3480156105db57600080fd5b506102eb6105ea366004611e8c565b610fde565b3480156105fb57600080fd5b506102eb61060a366004611ef9565b609c6020526000908152604090205481565b34801561062857600080fd5b506102eb610637366004611e8c565b611107565b34801561064857600080fd5b506102eb610657366004611e1a565b6113aa565b34801561066857600080fd5b5061067c610677366004611e8c565b6113c8565b60408051825181526020808401519082015291810151908201526060016102f5565b3480156106aa57600080fd5b506102eb6106b9366004611f3c565b61144b565b6104b56106cc366004611f75565b611476565b6001600160a01b0381166000908152609a6020526040812054600f81810b600160801b909204900b035b92915050565b60606068805461071090611ffa565b80601f016020809104026020016040519081016040528092919081815260200182805461073c90611ffa565b80156107895780601f1061075e57610100808354040283529160200191610789565b820191906000526020600020905b81548152906001019060200180831161076c57829003601f168201915b5050505050905090565b6001600160a01b0381166000908152606560205260408120546106fb90610e0a565b6000336107c381858561162c565b5060019392505050565b6000336107db858285611645565b6107e68585856116b9565b506001949350505050565b6001600160a01b0381166000908152609a6020526040812054600f81810b600160801b909204900b0381805b828110156108ae576001600160a01b0385166000908152609a6020526040812061084790836116d2565b6000818152609960209081526040918290208251606081018452815481526001820154928101929092526002015491810182905291925042106108945761088d8461202e565b935061089b565b50506108ae565b5050806108a79061202e565b905061081d565b509392505050565b6000336107c38185856108c9838361144b565b6108d39190611def565b61162c565b6000336120021461090057604051630f22c43960e41b815261200260048201526024016101f8565b6097546001600160a01b03166000908152606560205260408120549061092584610dcb565b90508181116109345780610936565b815b609754909150600090610952906001600160a01b031683611743565b6040519091506000906110029083908381818185875af1925050503d8060008114610999576040519150601f19603f3d011682016040523d82523d6000602084013e61099e565b606091505b50509050806109c0576040516312171d8360e31b815260040160405180910390fd5b50925050505b919050565b600033612002146109f357604051630f22c43960e41b815261200260048201526024016101f8565b81600003610a1457604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038316600090815260656020526040902054821115610a4d57604051631e9acf1760e31b815260040160405180910390fd5b610a578383611743565b905060006120026001600160a01b031663fc0c5ff16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abf9190611d9e565b610ac99042611def565b6040805160608101825285815260208101859052908101829052909150600085610af281611778565b60405160609290921b6bffffffffffffffffffffffff19166020830152603482015260540160408051601f1981840301815291815281516020928301206000818152609990935291205490915015610b5d5760405163b19e911560e01b815260040160405180910390fd5b600081815260996020908152604080832085518155828601516001820155818601516002909101556001600160a01b0389168352609a9091529020610bd990828154600160801b90819004600f0b6000818152600180860160205260409091209390935583546001600160801b03908116939091011602179055565b50505092915050565b60003361200214610c0a57604051630f22c43960e41b815261200260048201526024016101f8565b34600003610c2b57604051631f2a200560e01b815260040160405180910390fd5b610c3582346117a0565b9050806000036109c657604051639811e0c760e01b815260040160405180910390fd5b3361200214610c7e57604051630f22c43960e41b815261200260048201526024016101f8565b346000612710610c9867ffffffffffffffff851684612047565b610ca29190611dcd565b90506000610cb0828461205e565b905060006120026001600160a01b0316631fa8882b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d189190611d9e565b610d229042611dcd565b6098546000828152609d6020908152604080832093909355609c905290812080549293508492909190610d56908490611def565b925050819055508160986000828254610d6f9190611def565b9091555050609754610d8a906001600160a01b0316846117a0565b5060408051838152602081018590527ffb0e1482d62102ab9594f69d4c6d693749e3e2bf1c21af272f5456b2d5a4f6b5910160405180910390a15050505050565b6000609854600003610df0576040516307b76ce760e51b815260040160405180910390fd5b609854606754610e009084612047565b6106fb9190611dcd565b6000610e1560675490565b600003610e3557604051632fe8dae960e01b815260040160405180910390fd5b606754609854610e009084612047565b60606069805461071090611ffa565b60003381610e62828661144b565b905083811015610ec25760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016101f8565b6107e6828686840361162c565b60003361200214610ef757604051630f22c43960e41b815261200260048201526024016101f8565b81600003610f1857604051639811e0c760e01b815260040160405180910390fd5b6001600160a01b038316600090815260656020526040902054821115610f5157604051631e9acf1760e31b815260040160405180910390fd5b610f5b8383611743565b6040519091506000906120029083908381818185875af1925050503d8060008114610fa2576040519150601f19603f3d011682016040523d82523d6000602084013e610fa7565b606091505b5050905080610fc9576040516312171d8360e31b815260040160405180910390fd5b5092915050565b6000336107c38185856116b9565b6001600160a01b0382166000908152609a6020526040812054600f81810b600160801b909204900b03600003611016575060006106fb565b81158061104a57506001600160a01b0383166000908152609a6020526040902054600f81810b600160801b909204900b0382115b611054578161107e565b6001600160a01b0383166000908152609a6020526040902054600f81810b600160801b909204900b035b91506000805b838110156108ae576001600160a01b0385166000908152609a602052604081206110ae90836116d2565b600081815260996020908152604091829020825160608101845281548152600182015492810183905260029091015492810192909252919250906110f29085611def565b93505050806111009061202e565b9050611084565b6000336120021461112f57604051630f22c43960e41b815261200260048201526024016101f8565b6111376117c9565b6001600160a01b0383166000908152609a6020526040902054600f81810b600160801b909204900b036000036111805760405163ad41893760e01b815260040160405180910390fd5b8115806111b457506001600160a01b0383166000908152609a6020526040902054600f81810b600160801b909204900b0382115b6111be57816111e8565b6001600160a01b0383166000908152609a6020526040902054600f81810b600160801b909204900b035b915060005b821561129e576001600160a01b0384166000908152609a6020526040812061121490611822565b6000818152609960209081526040918290208251606081018452815481526001820154928101929092526002015491810182905291925042101561125957505061129e565b6001600160a01b0386166000908152609a6020526040902061127a90611876565b50602081015161128a9084611def565b925061129585612071565b945050506111ed565b806000036112bf576040516303cd8e0960e21b815260040160405180910390fd5b60006120026001600160a01b031663e8f67c3b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113259190611d9e565b90506000856001600160a01b03168284604051600060405180830381858888f193505050503d8060008114611376576040519150601f19603f3d011682016040523d82523d6000602084013e61137b565b606091505b505090508061139d576040516312171d8360e31b815260040160405180910390fd5b50506001805590506106fb565b6001600160a01b0381166000908152609b60205260408120546106fb565b6113ec60405180606001604052806000815260200160008152602001600081525090565b6001600160a01b0383166000908152609a6020526040812061140e90846116d2565b6000908152609960209081526040918290208251606081018452815481526001820154928101929092526002015491810191909152949350505050565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205490565b600054610100900460ff16158080156114965750600054600160ff909116105b806114b05750303b1580156114b0575060005460ff166001145b6115135760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016101f8565b6000805460ff191660011790558015611536576000805461ff0019166101001790555b336120021461155c57604051630f22c43960e41b815261200260048201526024016101f8565b60008383604051602001611571929190612088565b6040516020818303038152906040529050600084846040516020016115979291906120b8565b60405160208183030381529060405290506115b282826118fb565b6115ba611940565b609780546001600160a01b0319166001600160a01b0388161790556115de34611967565b50508015611626576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b604051632028747160e01b815260040160405180910390fd5b6000611651848461144b565b9050600019811461162657818110156116ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016101f8565b611626848484840361162c565b604051638cd22d1960e01b815260040160405180910390fd5b6000806116f56116e184611ad7565b85546116f09190600f0b6120d6565b611b45565b8454909150600160801b9004600f90810b9082900b1261172857604051632d0483c560e21b815260040160405180910390fd5b600f0b60009081526001939093016020525050604090205490565b600061174e82610e0a565b905061175a8383611ba9565b806098600082825461176c919061205e565b90915550909392505050565b6001600160a01b0381166000908152609b602052604090208054600181018255905b50919050565b60006117ab82610dcb565b90506117b78382611cdd565b816098600082825461176c9190611def565b60026001540361181b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101f8565b6002600155565b600061183d8254600f81810b600160801b909204900b131590565b1561185b57604051631ed9509560e11b815260040160405180910390fd5b508054600f0b60009081526001909101602052604090205490565b60006118918254600f81810b600160801b909204900b131590565b156118af57604051631ed9509560e11b815260040160405180910390fd5b508054600f0b6000818152600180840160205260408220805492905583546fffffffffffffffffffffffffffffffff191692016001600160801b03169190911790915590565b60018055565b600054610100900460ff166119225760405162461bcd60e51b81526004016101f8906120fe565b606861192e83826121ad565b50606961193b82826121ad565b505050565b600054610100900460ff166118f55760405162461bcd60e51b81526004016101f8906120fe565b600054610100900460ff1661198e5760405162461bcd60e51b81526004016101f8906120fe565b60006120026001600160a01b0316638a4d3fa86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190611d9e565b90508082111580611a0e57506097546001600160a01b0316155b80611a1a575060675415155b15611a3857604051632163e6b960e21b815260040160405180910390fd5b60006120026001600160a01b0316634e6fd6c46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9e919061226d565b9050611aaa8183611cdd565b6000611ab6838561205e565b609754909150611acf906001600160a01b031682611cdd565b505050609855565b60006001600160ff1b03821115611b415760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016101f8565b5090565b80600f81900b81146109c65760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016101f8565b6001600160a01b038216611c095760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016101f8565b6001600160a01b03821660009081526065602052604090205481811015611c7d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016101f8565b6001600160a01b03831660008181526065602090815260408083208686039055606780548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6001600160a01b038216611d335760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016101f8565b8060676000828254611d459190611def565b90915550506001600160a01b0382166000818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208284031215611db057600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600082611dea57634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156106fb576106fb611db7565b6001600160a01b0381168114611e1757600080fd5b50565b600060208284031215611e2c57600080fd5b8135611e3781611e02565b9392505050565b600060208083528351808285015260005b81811015611e6b57858101830151858201604001528201611e4f565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060408385031215611e9f57600080fd5b8235611eaa81611e02565b946020939093013593505050565b600080600060608486031215611ecd57600080fd5b8335611ed881611e02565b92506020840135611ee881611e02565b929592945050506040919091013590565b600060208284031215611f0b57600080fd5b5035919050565b600060208284031215611f2457600080fd5b813567ffffffffffffffff81168114611e3757600080fd5b60008060408385031215611f4f57600080fd5b8235611f5a81611e02565b91506020830135611f6a81611e02565b809150509250929050565b600080600060408486031215611f8a57600080fd5b8335611f9581611e02565b9250602084013567ffffffffffffffff80821115611fb257600080fd5b818601915086601f830112611fc657600080fd5b813581811115611fd557600080fd5b876020828501011115611fe757600080fd5b6020830194508093505050509250925092565b600181811c9082168061200e57607f821691505b60208210810361179a57634e487b7160e01b600052602260045260246000fd5b60006001820161204057612040611db7565b5060010190565b80820281158282048414176106fb576106fb611db7565b818103818111156106fb576106fb611db7565b60008161208057612080611db7565b506000190190565b65029ba30b5b2960d51b815281836006830137660810dc99591a5d60ca1b91016006810191909152600d01919050565b611cdd60f21b81528183600283013760009101600201908152919050565b80820182811260008312801582168215821617156120f6576120f6611db7565b505092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b601f82111561193b57600081815260208120601f850160051c810160208610156121865750805b601f850160051c820191505b818110156121a557828155600101612192565b505050505050565b815167ffffffffffffffff8111156121c7576121c7612149565b6121db816121d58454611ffa565b8461215f565b602080601f83116001811461221057600084156121f85750858301515b600019600386901b1c1916600185901b1785556121a5565b600085815260208120601f198616915b8281101561223f57888601518255948401946001909101908401612220565b508582101561225d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020828403121561227f57600080fd5b8151611e3781611e0256fea164736f6c6343000811000a" + }, + "0x0000000000000000000000000000000000002004": { + "balance": "0x0", + "code": "0x6080604052600436106103e85760003560e01c80637b3c71d311610208578063c28bc2fa11610118578063deaaa7cc116100ab578063ece40cc11161007a578063ece40cc114610e19578063f23a6e6114610e39578063f8ce560a14610e65578063fc0c546a14610e85578063fe0d94c114610ea657600080fd5b8063deaaa7cc14610cda578063e23a9a5214610d0e578063ea0217cf14610dd9578063eb9019d414610df957600080fd5b8063da95691a116100e7578063da95691a14610c2f578063dd42a1dd14610c4f578063dd4e2ba514610c74578063ddf0b00914610cba57600080fd5b8063c28bc2fa14610bbd578063c59057e414610bd0578063d07f91e914610bf0578063d33219b414610c1057600080fd5b8063a7713a701161019b578063b187bd261161016a578063b187bd2614610b23578063b58131b014610b41578063bc197c8114610b56578063c01f9e3714610b82578063c170ec0b14610ba257600080fd5b8063a7713a7014610aae578063a890c91014610ac3578063ab58fb8e14610ae3578063ac43175114610b0357600080fd5b806384b0196e116101d757806384b0196e14610a2657806391ddadf414610a4e57806397c3d33414610a7a5780639a802a6d14610a8e57600080fd5b80637b3c71d3146109bc5780637d5e81e2146109dc5780638129fc1c146109fc5780638456cb5914610a1157600080fd5b806332b8113e116103035780634838d1651161029657806354fd4d501161026557806354fd4d5014610912578063567813881461093c5780635f398a141461095c57806360c4247f1461097c57806370b0f6601461099c57600080fd5b80634838d1651461087c5780634a49ac4c146108ac5780634bf5d7e9146108cc578063533ddd14146108e157600080fd5b806340e58ee5116102d257806340e58ee5146107d1578063417c73a7146107f15780634385963214610811578063452115d61461085c57600080fd5b806332b8113e146107455780633932abb11461076e5780633bccf4fd146107845780633e4f49e6146107a457600080fd5b8063150b7a021161037b5780632656227d1161034a5780632656227d146106975780632d63f693146106aa5780632fe3e261146106e1578063328dd9821461071557600080fd5b8063150b7a02146105f0578063160cbed71461063457806317977c611461065457806324bc1a641461068257600080fd5b8063046f7da2116103b7578063046f7da21461054357806306f3f9e61461055857806306fdde0314610578578063143489d01461059a57600080fd5b8063013cf08b1461045857806301ffc9a7146104d357806302a251a314610503578063034201811461052357600080fd5b3661045357306103f6610eb9565b6001600160a01b0316146104515760405162461bcd60e51b815260206004820152601f60248201527f476f7665726e6f723a206d7573742073656e6420746f206578656375746f720060448201526064015b60405180910390fd5b005b600080fd5b34801561046457600080fd5b50610478610473366004615c65565b610ed3565b604080519a8b526001600160a01b0390991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015215156101008301521515610120820152610140015b60405180910390f35b3480156104df57600080fd5b506104f36104ee366004615c7e565b610f8e565b60405190151581526020016104ca565b34801561050f57600080fd5b50610195545b6040519081526020016104ca565b34801561052f57600080fd5b5061051561053e366004615dc4565b610f9f565b34801561054f57600080fd5b50610451611097565b34801561056457600080fd5b50610451610573366004615c65565b611127565b34801561058457600080fd5b5061058d6111b2565b6040516104ca9190615eba565b3480156105a657600080fd5b506105d86105b5366004615c65565b60009081526101636020526040902054600160401b90046001600160a01b031690565b6040516001600160a01b0390911681526020016104ca565b3480156105fc57600080fd5b5061061b61060b366004615ee2565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016104ca565b34801561064057600080fd5b5061051561064f3660046160b9565b611245565b34801561066057600080fd5b5061051561066f366004616148565b6102c36020526000908152604090205481565b34801561068e57600080fd5b50610515611330565b6105156106a53660046160b9565b611356565b3480156106b657600080fd5b506105156106c5366004615c65565b600090815261016360205260409020546001600160401b031690565b3480156106ed57600080fd5b506105157fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af8881565b34801561072157600080fd5b50610735610730366004615c65565b611449565b6040516104ca949392919061622e565b34801561075157600080fd5b5061028f546040516001600160401b0390911681526020016104ca565b34801561077a57600080fd5b5061019454610515565b34801561079057600080fd5b5061051561079f36600461627b565b6116db565b3480156107b057600080fd5b506107c46107bf366004615c65565b611751565b6040516104ca91906162df565b3480156107dd57600080fd5b506104516107ec366004615c65565b61175c565b3480156107fd57600080fd5b5061045161080c366004616148565b611787565b34801561081d57600080fd5b506104f361082c366004616307565b60008281526101c6602090815260408083206001600160a01b038516845260080190915290205460ff1692915050565b34801561086857600080fd5b506105156108773660046160b9565b611808565b34801561088857600080fd5b506104f3610897366004616148565b60016020526000908152604090205460ff1681565b3480156108b857600080fd5b506104516108c7366004616148565b611816565b3480156108d857600080fd5b5061058d611891565b3480156108ed57600080fd5b506104f36108fc366004616148565b6102c16020526000908152604090205460ff1681565b34801561091e57600080fd5b506040805180820190915260018152603160f81b602082015261058d565b34801561094857600080fd5b50610515610957366004616337565b61193e565b34801561096857600080fd5b50610515610977366004616363565b611967565b34801561098857600080fd5b50610515610997366004615c65565b6119b1565b3480156109a857600080fd5b506104516109b7366004615c65565b611a66565b3480156109c857600080fd5b506105156109d73660046163e6565b611aee565b3480156109e857600080fd5b506105156109f736600461643f565b611b40565b348015610a0857600080fd5b50610451611c5b565b348015610a1d57600080fd5b50610451611e89565b348015610a3257600080fd5b50610a3b611f1f565b6040516104ca97969594939291906164df565b348015610a5a57600080fd5b50610a63611fbd565b60405165ffffffffffff90911681526020016104ca565b348015610a8657600080fd5b506064610515565b348015610a9a57600080fd5b50610515610aa9366004616541565b612031565b348015610aba57600080fd5b50610515612048565b348015610acf57600080fd5b50610451610ade366004616148565b612075565b348015610aef57600080fd5b50610515610afe366004615c65565b6120fd565b348015610b0f57600080fd5b50610451610b1e366004616599565b612199565b348015610b2f57600080fd5b5060005462010000900460ff166104f3565b348015610b4d57600080fd5b506105156128de565b348015610b6257600080fd5b5061061b610b713660046165f8565b63bc197c8160e01b95945050505050565b348015610b8e57600080fd5b50610515610b9d366004615c65565b6128ea565b348015610bae57600080fd5b506102c2546104f39060ff1681565b610451610bcb36600461668b565b6128f5565b348015610bdc57600080fd5b50610515610beb3660046160b9565b612a05565b348015610bfc57600080fd5b50610451610c0b3660046166ce565b612a3f565b348015610c1c57600080fd5b5061022b546001600160a01b03166105d8565b348015610c3b57600080fd5b50610515610c4a3660046166f7565b612ac7565b348015610c5b57600080fd5b50600054630100000090046001600160a01b03166105d8565b348015610c8057600080fd5b5060408051808201909152601a81527f737570706f72743d627261766f2671756f72756d3d627261766f000000000000602082015261058d565b348015610cc657600080fd5b50610451610cd5366004615c65565b612b4e565b348015610ce657600080fd5b506105157f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b348015610d1a57600080fd5b50610da9610d29366004616307565b60408051606081018252600080825260208201819052918101919091525060009182526101c6602090815260408084206001600160a01b0393909316845260089092018152918190208151606081018352905460ff8082161515835261010082041693820193909352620100009092046001600160601b03169082015290565b6040805182511515815260208084015160ff1690820152918101516001600160601b0316908201526060016104ca565b348015610de557600080fd5b50610451610df4366004615c65565b612b71565b348015610e0557600080fd5b50610515610e14366004616798565b612bf9565b348015610e2557600080fd5b50610451610e34366004615c65565b612c1a565b348015610e4557600080fd5b5061061b610e543660046167c4565b63f23a6e6160e01b95945050505050565b348015610e7157600080fd5b50610515610e80366004615c65565b612ca2565b348015610e9157600080fd5b506101f8546105d8906001600160a01b031681565b610451610eb4366004615c65565b612d31565b6000610ece61022b546001600160a01b031690565b905090565b8060008080808080808080610ee78a6120fd565b60008c815261016360205260409020549098506001600160401b03169650610f0e8b6128ea565b60008c81526101c66020526040812080546005820154600683015460078401546001600160a01b039093169e50949a509850929650919450610f4f8d611751565b90506002816007811115610f6557610f656162c9565b1493506007816007811115610f7c57610f7c6162c9565b14925050509193959799509193959799565b6000610f9982612d54565b92915050565b60008061104361103b7fb3b3f3b703cd84ce352197dcff232b1b5d3cfb2025ce47cf04742d0651f1af888c8c8c8c604051610fdb92919061682c565b60405180910390208b80519060200120604051602001611020959493929190948552602085019390935260ff9190911660408401526060830152608082015260a00190565b60405160208183030381529060405280519060200120612d79565b868686612da6565b90506110898a828b8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d9250612dc4915050565b9a9950505050505050505050565b600054630100000090046001600160a01b031633146110c9576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff166110f257604051636cd6020160e01b815260040160405180910390fd5b6000805462ff0000191681556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f99190a1565b61112f610eb9565b6001600160a01b0316336001600160a01b03161461115f5760405162461bcd60e51b81526004016104489061683c565b30611168610eb9565b6001600160a01b0316146111a6576000803660405161118892919061682c565b604051809103902090505b8061119f610164612e2d565b0361119357505b6111af81612eac565b50565b606061016280546111c290616873565b80601f01602080910402602001604051908101604052809291908181526020018280546111ee90616873565b801561123b5780601f106112105761010080835404028352916020019161123b565b820191906000526020600020905b81548152906001019060200180831161121e57829003601f168201915b5050505050905090565b6000805462010000900460ff161561127057604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff16156112a15760405163b1d02c3d60e01b815260040160405180910390fd5b60005b855181101561131a576102c160008783815181106112c4576112c46168ad565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1661130857604051630b094f2760e31b815260040160405180910390fd5b80611312816168d9565b9150506112a4565b506113278585858561301d565b95945050505050565b6000610ece600161133f611fbd565b61134991906168f2565b65ffffffffffff16612ca2565b60008061136586868686612a05565b9050600061137282611751565b90506004816007811115611388576113886162c9565b14806113a5575060058160078111156113a3576113a36162c9565b145b6113c15760405162461bcd60e51b815260040161044890616918565b6000828152610163602052604090819020600201805460ff19166001179055517f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f906114109084815260200190565b60405180910390a16114258288888888613222565b61143282888888886132c3565b61143f82888888886133a5565b5095945050505050565b60608060608060006101c66000878152602001908152602001600020905080600101816002018260030183600401838054806020026020016040519081016040528092919081815260200182805480156114cc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114ae575b505050505093508280548060200260200160405190810160405280929190818152602001828054801561151e57602002820191906000526020600020905b81548152602001906001019080831161150a575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156115f257838290600052602060002001805461156590616873565b80601f016020809104026020016040519081016040528092919081815260200182805461159190616873565b80156115de5780601f106115b3576101008083540402835291602001916115de565b820191906000526020600020905b8154815290600101906020018083116115c157829003601f168201915b505050505081526020019060010190611546565b50505050915080805480602002602001604051908101604052809291908181526020016000905b828210156116c557838290600052602060002001805461163890616873565b80601f016020809104026020016040519081016040528092919081815260200182805461166490616873565b80156116b15780601f10611686576101008083540402835291602001916116b1565b820191906000526020600020905b81548152906001019060200180831161169457829003601f168201915b505050505081526020019060010190611619565b5050505090509450945094509450509193509193565b604080517f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f602082015290810186905260ff8516606082015260009081906117299061103b90608001611020565b9050611746878288604051806020016040528060008152506133e0565b979650505050505050565b6000610f9982613403565b60008060008061176b85613550565b935093509350935061177f84848484611808565b505050505050565b600054630100000090046001600160a01b031633146117b9576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600160208190526040808320805460ff1916909217909155517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b6000611327858585856137e1565b600054630100000090046001600160a01b03163314611848576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260016020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b6101f85460408051634bf5d7e960e01b815290516060926001600160a01b031691634bf5d7e99160048083019260009291908290030181865afa9250505080156118fd57506040513d6000823e601f3d908101601f191682016040526118fa9190810190616959565b60015b611939575060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b919050565b60008033905061195f848285604051806020016040528060008152506133e0565b949350505050565b60008033905061174687828888888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250612dc4915050565b61025e546000908082036119ca57505061025d54919050565b600061025e6119da6001846169c6565b815481106119ea576119ea6168ad565b60009182526020918290206040805180820190915291015463ffffffff8116808352600160201b9091046001600160e01b03169282019290925291508410611a4057602001516001600160e01b03169392505050565b611a55611a4c856138ac565b61025e90613915565b6001600160e01b0316949350505050565b611a6e610eb9565b6001600160a01b0316336001600160a01b031614611a9e5760405162461bcd60e51b81526004016104489061683c565b30611aa7610eb9565b6001600160a01b031614611ae55760008036604051611ac792919061682c565b604051809103902090505b80611ade610164612e2d565b03611ad257505b6111af816139c8565b600080339050611b3686828787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506133e092505050565b9695505050505050565b6000805462010000900460ff1615611b6b57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615611b9c5760405163b1d02c3d60e01b815260040160405180910390fd5b611ba4613a0b565b3360009081526102c360205260409020548015611c19576000611bc682611751565b90506001816007811115611bdc57611bdc6162c9565b1480611bf957506000816007811115611bf757611bf76162c9565b145b15611c175760405163867f3ee560e01b815260040160405180910390fd5b505b825160208401206000611c2e88888885612a05565b3360009081526102c3602052604090208190559050611c4f88888888613ab6565b98975050505050505050565b600054610100900460ff1615808015611c7b5750600054600160ff909116105b80611c955750303b158015611c95575060005460ff166001145b611cf85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610448565b6000805460ff191660011790558015611d1b576000805461ff0019166101001790555b334114611d3b5760405163022d8c9560e31b815260040160405180910390fd5b3a15611d5a576040516383f1b1d360e01b815260040160405180910390fd5b611d866040518060400160405280600b81526020016a2129a1a3b7bb32b93737b960a91b815250613b1e565b611db0611d95600360006169ef565b611da1600360786169ef565b680ad78ebc5ac6200000613b75565b611db8613bac565b611dc3612005613bd3565b611dce612006613c03565b611dd8600a613c33565b611dec611de76003603c6169ef565b613c63565b6110076000526102c16020527f2f832952f0ef896b8c8edd6d16a2e4f2591a90375e33021e3b9ff197f3793fc0805460ff19166001179055611e417304d63abcd2b9b1baa327f2dda0f873f197ccd186613c93565b80156111af576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b600054630100000090046001600160a01b03163314611ebb576040516306fbb1e360e01b815260040160405180910390fd5b60005462010000900460ff1615611ee557604051631785c68160e01b815260040160405180910390fd5b6000805462ff00001916620100001781556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e7529190a1565b6000606080600080600060606098546000801b148015611f3f5750609954155b611f835760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b6044820152606401610448565b611f8b613ce6565b611f93613cf5565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6101f854604080516324776b7d60e21b815290516000926001600160a01b0316916391ddadf49160048083019260209291908290030181865afa925050508015612024575060408051601f3d908101601f1916820190925261202191810190616a11565b60015b61193957610ece43613d04565b600061203e848484613d6b565b90505b9392505050565b61025e546000901561206d5761205f61025e613de2565b6001600160e01b0316905090565b5061025d5490565b61207d610eb9565b6001600160a01b0316336001600160a01b0316146120ad5760405162461bcd60e51b81526004016104489061683c565b306120b6610eb9565b6001600160a01b0316146120f457600080366040516120d692919061682c565b604051809103902090505b806120ed610164612e2d565b036120e157505b6111af81613e12565b61022b54600082815261022c602052604080822054905163d45c443560e01b81526004810191909152909182916001600160a01b039091169063d45c443590602401602060405180830381865afa15801561215c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121809190616a39565b9050806001146121905780612041565b60009392505050565b33611007146121bf57604051630f22c43960e41b81526110076004820152602401610448565b6122256040518060400160405280600b81526020016a766f74696e6744656c617960a81b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613e7d9050565b156122da57602081146122535783838383604051630a5a604160e01b81526004016104489493929190616a7b565b604080516020601f8401819004810282018101909252828152600091612294918585808385018382808284376000920191909152509293925050613ed69050565b90508015806122a557506201518081115b156122cb5784848484604051630a5a604160e01b81526004016104489493929190616a7b565b6122d4816139c8565b5061289b565b6123416040518060400160405280600c81526020016b1d9bdd1a5b99d4195c9a5bd960a21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613e7d9050565b156123f0576020811461236f5783838383604051630a5a604160e01b81526004016104489493929190616a7b565b604080516020601f84018190048102820181019092528281526000916123b0918585808385018382808284376000920191909152509293925050613ed69050565b90508015806123c1575062278d0081115b156123e75784848484604051630a5a604160e01b81526004016104489493929190616a7b565b6122d481613edb565b61245c604051806040016040528060118152602001701c1c9bdc1bdcd85b151a1c995cda1bdb19607a1b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613e7d9050565b15612512576020811461248a5783838383604051630a5a604160e01b81526004016104489493929190616a7b565b604080516020601f84018190048102820181019092528281526000916124cb918585808385018382808284376000920191909152509293925050613ed69050565b90508015806124e3575069021e19e0c9bab240000081115b156125095784848484604051630a5a604160e01b81526004016104489493929190616a7b565b6122d481613f7e565b61257c6040518060400160405280600f81526020016e38bab7b93ab6a73ab6b2b930ba37b960891b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613e7d9050565b1561262b57602081146125aa5783838383604051630a5a604160e01b81526004016104489493929190616a7b565b604080516020601f84018190048102820181019092528281526000916125eb918585808385018382808284376000920191909152509293925050613ed69050565b905060058110806125fc5750601481115b156126225784848484604051630a5a604160e01b81526004016104489493929190616a7b565b6122d481612eac565b61269a604051806040016040528060148152602001736d696e506572696f64416674657251756f72756d60601b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613e7d9050565b1561276057600881146126c85783838383604051630a5a604160e01b81526004016104489493929190616a7b565b600061270e600884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ed69050565b90506001600160401b038116158061273157506202a300816001600160401b0316115b156127575784848484604051630a5a604160e01b81526004016104489493929190616a7b565b6122d481613fc1565b6127cc6040518060400160405280601181526020017033b7bb32b93737b9283937ba32b1ba37b960791b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613e7d9050565b1561287a57601481146127fa5783838383604051630a5a604160e01b81526004016104489493929190616a7b565b6000612840601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050613ed69050565b90506001600160a01b0381166128715784848484604051630a5a604160e01b81526004016104489493929190616a7b565b6122d48161402d565b838383836040516325ee20d560e21b81526004016104489493929190616a7b565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e633848484846040516128d09493929190616a7b565b60405180910390a150505050565b6000610ece6101965490565b6000610f9982614099565b6128fd610eb9565b6001600160a01b0316336001600160a01b03161461292d5760405162461bcd60e51b81526004016104489061683c565b30612936610eb9565b6001600160a01b031614612974576000803660405161295692919061682c565b604051809103902090505b8061296d610164612e2d565b0361296157505b600080856001600160a01b031685858560405161299292919061682c565b60006040518083038185875af1925050503d80600081146129cf576040519150601f19603f3d011682016040523d82523d6000602084013e6129d4565b606091505b50915091506129fc8282604051806060016040528060288152602001616ed8602891396140d7565b50505050505050565b600084848484604051602001612a1e9493929190616aa2565b60408051601f19818403018152919052805160209091012095945050505050565b612a47610eb9565b6001600160a01b0316336001600160a01b031614612a775760405162461bcd60e51b81526004016104489061683c565b30612a80610eb9565b6001600160a01b031614612abe5760008036604051612aa092919061682c565b604051809103902090505b80612ab7610164612e2d565b03612aab57505b6111af81613fc1565b60008251845114612b2b5760405162461bcd60e51b815260206004820152602860248201527f476f7665726e6f72427261766f3a20696e76616c6964207369676e61747572656044820152670e640d8cadccee8d60c31b6064820152608401610448565b612b393387878787876140f0565b611b368686612b4887876141ae565b85611b40565b600080600080612b5d85613550565b935093509350935061177f84848484611245565b612b79610eb9565b6001600160a01b0316336001600160a01b031614612ba95760405162461bcd60e51b81526004016104489061683c565b30612bb2610eb9565b6001600160a01b031614612bf05760008036604051612bd292919061682c565b604051809103902090505b80612be9610164612e2d565b03612bdd57505b6111af81613edb565b60006120418383612c1560408051602081019091526000815290565b613d6b565b612c22610eb9565b6001600160a01b0316336001600160a01b031614612c525760405162461bcd60e51b81526004016104489061683c565b30612c5b610eb9565b6001600160a01b031614612c995760008036604051612c7b92919061682c565b604051809103902090505b80612c92610164612e2d565b03612c8657505b6111af81613f7e565b60006064612caf836119b1565b6101f854604051632394e7a360e21b8152600481018690526001600160a01b0390911690638e539e8c90602401602060405180830381865afa158015612cf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1d9190616a39565b612d279190616aed565b610f9991906169ef565b600080600080612d4085613550565b935093509350935061177f84848484611356565b60006001600160e01b03198216636e665ced60e01b1480610f995750610f99826142e0565b6000610f99612d8661437c565b8360405161190160f01b8152600281019290925260228201526042902090565b6000806000612db787878787614386565b9150915061143f8161444a565b6000805462010000900460ff1615612def57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff1615612e205760405163b1d02c3d60e01b815260040160405180910390fd5b611b368686868686614594565b6000612e488254600f81810b600160801b909204900b131590565b15612e6657604051631ed9509560e11b815260040160405180910390fd5b508054600f0b6000818152600180840160205260408220805492905583546fffffffffffffffffffffffffffffffff191692016001600160801b03169190911790915590565b6064811115612f2f5760405162461bcd60e51b815260206004820152604360248201527f476f7665726e6f72566f74657351756f72756d4672616374696f6e3a2071756f60448201527f72756d4e756d657261746f72206f7665722071756f72756d44656e6f6d696e616064820152623a37b960e91b608482015260a401610448565b6000612f39612048565b90508015801590612f4b575061025e54155b15612fb057604080518082019091526000815261025e9060208101612f6f84614697565b6001600160e01b039081169091528254600181018455600093845260209384902083519490930151909116600160201b0263ffffffff909316929092179101555b612fde612fcb612fbe611fbd565b65ffffffffffff166138ac565b612fd484614697565b61025e9190614700565b505060408051828152602081018490527f0553476bf02ef2726e8ce5ced78d63e26e602e4a2257b1f559418e24b4633997910160405180910390a15050565b60008061302c86868686612a05565b9050600461303982611751565b600781111561304a5761304a6162c9565b146130675760405162461bcd60e51b815260040161044890616918565b61022b546040805163793d064960e11b815290516000926001600160a01b03169163f27a0c929160048083019260209291908290030181865afa1580156130b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d69190616a39565b61022b5460405163b1c5f42760e01b81529192506001600160a01b03169063b1c5f42790613111908a908a908a906000908b90600401616b04565b602060405180830381865afa15801561312e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131529190616a39565b600083815261022c60205260408082209290925561022b5491516308f2a0bb60e41b81526001600160a01b0390921691638f2a0bb09161319f918b918b918b91908b908990600401616b52565b600060405180830381600087803b1580156131b957600080fd5b505af11580156131cd573d6000803e3d6000fd5b505050507f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda28928282426131ff9190616baa565b604080519283526020830191909152015b60405180910390a15095945050505050565b3061322b610eb9565b6001600160a01b0316146132bc5760005b845181101561177f57306001600160a01b0316858281518110613261576132616168ad565b60200260200101516001600160a01b0316036132ac576132ac83828151811061328c5761328c6168ad565b60200260200101518051906020012061016461471b90919063ffffffff16565b6132b5816168d9565b905061323c565b5050505050565b60005462010000900460ff16156132ed57604051631785c68160e01b815260040160405180910390fd5b3360009081526001602052604090205460ff161561331e5760405163b1d02c3d60e01b815260040160405180910390fd5b60005b8451811015613397576102c16000868381518110613341576133416168ad565b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1661338557604051630b094f2760e31b815260040160405180910390fd5b8061338f816168d9565b915050613321565b506132bc8585858585614757565b306133ae610eb9565b6001600160a01b0316146132bc5761016454600f81810b600160801b909204900b13156132bc576000610164556132bc565b6000611327858585856133fe60408051602081019091526000815290565b612dc4565b60008061340f836147cc565b90506004816007811115613425576134256162c9565b146134305792915050565b600083815261022c60205260409020548061344c575092915050565b61022b54604051632ab0f52960e01b8152600481018390526001600160a01b0390911690632ab0f52990602401602060405180830381865afa158015613496573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ba9190616bbd565b156134c9575060079392505050565b61022b54604051632c258a9f60e11b8152600481018390526001600160a01b039091169063584b153e90602401602060405180830381865afa158015613513573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135379190616bbd565b15613546575060059392505050565b5060029392505050565b60608060606000806101c660008781526020019081526020016000209050806001018160020161372283600301805480602002602001604051908101604052809291908181526020016000905b828210156136495783829060005260206000200180546135bc90616873565b80601f01602080910402602001604051908101604052809291908181526020018280546135e890616873565b80156136355780601f1061360a57610100808354040283529160200191613635565b820191906000526020600020905b81548152906001019060200180831161361857829003601f168201915b50505050508152602001906001019061359d565b50505060048601805460408051602080840282018101909252828152935060009084015b8282101561371957838290600052602060002001805461368c90616873565b80601f01602080910402602001604051908101604052809291908181526020018280546136b890616873565b80156137055780601f106136da57610100808354040283529160200191613705565b820191906000526020600020905b8154815290600101906020018083116136e857829003601f168201915b50505050508152602001906001019061366d565b505050506141ae565b600984015483546040805160208084028201810190925282815291869183018282801561377857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161375a575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156137ca57602002820191906000526020600020905b8154815260200190600101908083116137b6575b505050505092509450945094509450509193509193565b6000806137f086868686612a05565b60008181526101c660205260409020549091506001600160a01b031633811480613844575061381d6128de565b61384282600161382b611fbd565b61383591906168f2565b65ffffffffffff16612bf9565b105b6138a05760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f72427261766f3a2070726f706f7365722061626f76652074686044820152661c995cda1bdb1960ca1b6064820152608401610448565b61174687878787614904565b600063ffffffff8211156139115760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610448565b5090565b81546000908181600581111561397257600061393084614912565b61393a90856169c6565b60008881526020902090915081015463ffffffff908116908716101561396257809150613970565b61396d816001616baa565b92505b505b6000613980878785856149fa565b905080156139bb576139a5876139976001846169c6565b600091825260209091200190565b54600160201b90046001600160e01b0316611746565b6000979650505050505050565b6101945460408051918252602082018390527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a93910160405180910390a161019455565b6102c25460ff16613ab4576a084595161401484a0000006120056001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a869190616a39565b1015613aa5576040516311b6707f60e01b815260040160405180910390fd5b6102c2805460ff191660011790555b565b6000613b1233868686516001600160401b03811115613ad757613ad7615d01565b604051908082528060200260200182016040528015613b0a57816020015b6060815260200190600190039081613af55790505b5087876140f0565b61132785858585614a50565b600054610100900460ff16613b455760405162461bcd60e51b815260040161044890616bdf565b613b6c81613b676040805180820190915260018152603160f81b602082015290565b614e2f565b6111af81614e7e565b600054610100900460ff16613b9c5760405162461bcd60e51b815260040161044890616bdf565b613ba7838383614eb6565b505050565b600054610100900460ff16613ab45760405162461bcd60e51b815260040161044890616bdf565b600054610100900460ff16613bfa5760405162461bcd60e51b815260040161044890616bdf565b6111af81614ef8565b600054610100900460ff16613c2a5760405162461bcd60e51b815260040161044890616bdf565b6111af81614f42565b600054610100900460ff16613c5a5760405162461bcd60e51b815260040161044890616bdf565b6111af81614f69565b600054610100900460ff16613c8a5760405162461bcd60e51b815260040161044890616bdf565b6111af81614f90565b600054610100900460ff16613cba5760405162461bcd60e51b815260040161044890616bdf565b600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b6060609a80546111c290616873565b6060609b80546111c290616873565b600065ffffffffffff8211156139115760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b6064820152608401610448565b6101f854604051630748d63560e31b81526001600160a01b038581166004830152602482018590526000921690633a46b1a890604401602060405180830381865afa158015613dbe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203e9190616a39565b8054600090801561219057613dfc836139976001846169c6565b54600160201b90046001600160e01b0316612041565b61022b54604080516001600160a01b03928316815291831660208301527f08f74ea46ef7894f65eabfb5e6e695de773a000b47c529ab559178069b226401910160405180910390a161022b80546001600160a01b0319166001600160a01b0392909216919091179055565b600081604051602001613e909190616c2a565b6040516020818303038152906040528051906020012083604051602001613eb79190616c2a565b6040516020818303038152906040528051906020012014905092915050565b015190565b60008111613f3b5760405162461bcd60e51b815260206004820152602760248201527f476f7665726e6f7253657474696e67733a20766f74696e6720706572696f6420604482015266746f6f206c6f7760c81b6064820152608401610448565b6101955460408051918252602082018390527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e8828910160405180910390a161019555565b6101965460408051918252602082018390527fccb45da8d5717e6c4544694297c4ba5cf151d455c9bb0ed4fc7a38411bc05461910160405180910390a161019655565b61028f54604080516001600160401b03928316815291831660208301527f7ca4ac117ed3cdce75c1161d8207c440389b1a15d69d096831664657c07dafc2910160405180910390a161028f805467ffffffffffffffff19166001600160401b0392909216919091179055565b600080546040516001600160a01b0380851693630100000090930416917f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b91a3600080546001600160a01b039092166301000000026301000000600160b81b0319909216919091179055565b60008181526101636020526040812060010154610f99906001600160401b0316600084815261029060205260409020546001600160401b0316614fb7565b606083156140e6575081612041565b6120418383614fcd565b80516020820120600061410e878761410888886141ae565b85612a05565b60008181526101c6602052604090206009810154919250906141a35780546001600160a01b0319166001600160a01b038a16178155875161415890600183019060208b0190615a9c565b50865161416e90600283019060208a0190615afd565b5085516141849060038301906020890190615b38565b50845161419a9060048301906020880190615b8a565b50600981018390555b505050505050505050565b6060600082516001600160401b038111156141cb576141cb615d01565b6040519080825280602002602001820160405280156141fe57816020015b60608152602001906001900390816141e95790505b50905060005b81518110156142d85784818151811061421f5761421f6168ad565b60200260200101515160001461428f57848181518110614241576142416168ad565b602002602001015180519060200120848281518110614262576142626168ad565b602002602001015160405160200161427b929190616c46565b6040516020818303038152906040526142aa565b8381815181106142a1576142a16168ad565b60200260200101515b8282815181106142bc576142bc6168ad565b6020026020010181905250806142d1906168d9565b9050614204565b509392505050565b600063288ace0360e11b6318df743f60e31b63bf26d89760e01b6379dd796f60e01b6001600160e01b0319861682148061432657506001600160e01b0319868116908216145b8061433d57506001600160e01b0319868116908516145b8061435857506001600160e01b03198616630271189760e51b145b80611b3657506301ffc9a760e01b6001600160e01b03198716149695505050505050565b6000610ece614ff7565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156143bd5750600090506003614441565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614411573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661443a57600060019250925050614441565b9150600090505b94509492505050565b600081600481111561445e5761445e6162c9565b036144665750565b600181600481111561447a5761447a6162c9565b036144c75760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610448565b60028160048111156144db576144db6162c9565b036145285760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610448565b600381600481111561453c5761453c6162c9565b036111af5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610448565b6000806145a4878787878761506b565b600088815261029060205260409020549091506001600160401b03161580156145d157506145d1876151c1565b15611b365760006145eb61028f546001600160401b031690565b6145f3611fbd565b65ffffffffffff166146059190616c77565b9050614610886128ea565b816001600160401b0316111561465f576040516001600160401b038216815288907f541f725fb9f7c98a30cc9c0ff32fbb14358cd7159c847a3aa20a2bdc442ba5119060200160405180910390a25b600088815261029060205260409020805467ffffffffffffffff19166001600160401b03929092169190911790559695505050505050565b60006001600160e01b038211156139115760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610448565b60008061470e858585615201565b915091505b935093915050565b8154600160801b90819004600f0b6000818152600180860160205260409091209390935583546001600160801b03908116939091011602179055565b61022b5460405163e38335e560e01b81526001600160a01b039091169063e38335e5903490614793908890889088906000908990600401616b04565b6000604051808303818588803b1580156147ac57600080fd5b505af11580156147c0573d6000803e3d6000fd5b50505050505050505050565b600081815261016360205260408120600281015460ff16156147f15750600792915050565b6002810154610100900460ff161561480c5750600292915050565b600083815261016360205260408120546001600160401b0316908190036148755760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a20756e6b6e6f776e2070726f706f73616c2069640000006044820152606401610448565b600061487f611fbd565b65ffffffffffff16905080821061489b57506000949350505050565b60006148a6866128ea565b90508181106148bb5750600195945050505050565b6148c4866151c1565b80156148e7575060008681526101c6602052604090206006810154600590910154115b156148f85750600495945050505050565b50600395945050505050565b6000611327858585856153a0565b60008160000361492457506000919050565b6000600161493184615456565b901c6001901b9050600181848161494a5761494a6169d9565b048201901c90506001818481614962576149626169d9565b048201901c9050600181848161497a5761497a6169d9565b048201901c90506001818481614992576149926169d9565b048201901c905060018184816149aa576149aa6169d9565b048201901c905060018184816149c2576149c26169d9565b048201901c905060018184816149da576149da6169d9565b048201901c9050612041818285816149f4576149f46169d9565b046154ea565b60005b818310156142d8576000614a1184846154f9565b60008781526020902090915063ffffffff86169082015463ffffffff161115614a3c57809250614a4a565b614a47816001616baa565b93505b506149fd565b600033614a5d8184615514565b614aa95760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73657220726573747269637465640000006044820152606401610448565b6000614ab3611fbd565b65ffffffffffff169050614ac56128de565b614ad483610e146001856169c6565b1015614b3c5760405162461bcd60e51b815260206004820152603160248201527f476f7665726e6f723a2070726f706f73657220766f7465732062656c6f7720706044820152701c9bdc1bdcd85b081d1a1c995cda1bdb19607a1b6064820152608401610448565b6000614b518888888880519060200120612a05565b90508651885114614b745760405162461bcd60e51b815260040161044890616c97565b8551885114614b955760405162461bcd60e51b815260040161044890616c97565b6000885111614be65760405162461bcd60e51b815260206004820152601860248201527f476f7665726e6f723a20656d7074792070726f706f73616c00000000000000006044820152606401610448565b600081815261016360205260409020546001600160401b031615614c565760405162461bcd60e51b815260206004820152602160248201527f476f7665726e6f723a2070726f706f73616c20616c72656164792065786973746044820152607360f81b6064820152608401610448565b6000614c626101945490565b614c6c9084616baa565b90506000614c7a6101955490565b614c849083616baa565b90506040518060e00160405280614c9a84615605565b6001600160401b031681526001600160a01b038716602082015260006040820152606001614cc783615605565b6001600160401b03908116825260006020808401829052604080850183905260609485018390528883526101638252918290208551815492870151878501519186166001600160e01b031990941693909317600160401b6001600160a01b039094168402176001600160e01b0316600160e01b60e09290921c91909102178155938501516080860151908416921c0217600183015560a08301516002909201805460c09094015161ffff1990941692151561ff00191692909217610100931515939093029290921790558a517f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e091859188918e918e91811115614dcc57614dcc615d01565b604051908082528060200260200182016040528015614dff57816020015b6060815260200190600190039081614dea5790505b508d88888f604051614e1999989796959493929190616cd8565b60405180910390a1509098975050505050505050565b600054610100900460ff16614e565760405162461bcd60e51b815260040161044890616bdf565b609a614e628382616db6565b50609b614e6f8282616db6565b50506000609881905560995550565b600054610100900460ff16614ea55760405162461bcd60e51b815260040161044890616bdf565b610162614eb28282616db6565b5050565b600054610100900460ff16614edd5760405162461bcd60e51b815260040161044890616bdf565b614ee6836139c8565b614eef82613edb565b613ba781613f7e565b600054610100900460ff16614f1f5760405162461bcd60e51b815260040161044890616bdf565b6101f880546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166120f45760405162461bcd60e51b815260040161044890616bdf565b600054610100900460ff166111a65760405162461bcd60e51b815260040161044890616bdf565b600054610100900460ff16612abe5760405162461bcd60e51b815260040161044890616bdf565b6000818311614fc65781612041565b5090919050565b815115614fdd5781518083602001fd5b8060405162461bcd60e51b81526004016104489190615eba565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61502261566d565b61502a6156c6565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600085815261016360205260408120600161508588611751565b6007811115615096576150966162c9565b146150ef5760405162461bcd60e51b815260206004820152602360248201527f476f7665726e6f723a20766f7465206e6f742063757272656e746c792061637460448201526269766560e81b6064820152608401610448565b80546000906151099088906001600160401b031686613d6b565b905061511888888884886156f7565b835160000361516d57866001600160a01b03167fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda4898884896040516151609493929190616e75565b60405180910390a2611746565b866001600160a01b03167fe2babfbac5889a709b63bb7f598b324e08bc5a4fb9ec647fb3cbc9ec07eb871289888489896040516151ae959493929190616e9d565b60405180910390a2979650505050505050565b60008181526101c66020526040812060058101546151f8610e8085600090815261016360205260409020546001600160401b031690565b11159392505050565b82546000908190801561534757600061521f876139976001856169c6565b60408051808201909152905463ffffffff808216808452600160201b9092046001600160e01b0316602084015291925090871610156152a05760405162461bcd60e51b815260206004820152601b60248201527f436865636b706f696e743a2064656372656173696e67206b65797300000000006044820152606401610448565b805163ffffffff8088169116036152e857846152c1886139976001866169c6565b80546001600160e01b0392909216600160201b0263ffffffff909216919091179055615337565b6040805180820190915263ffffffff80881682526001600160e01b0380881660208085019182528b54600181018d5560008d81529190912094519151909216600160201b029216919091179101555b6020015192508391506147139050565b50506040805180820190915263ffffffff80851682526001600160e01b0380851660208085019182528854600181018a5560008a815291822095519251909316600160201b029190931617920191909155905081614713565b6000806153af86868686615895565b600081815261022c6020526040902054909150156113275761022b54600082815261022c60205260409081902054905163c4d252f560e01b81526001600160a01b039092169163c4d252f59161540b9160040190815260200190565b600060405180830381600087803b15801561542557600080fd5b505af1158015615439573d6000803e3d6000fd5b505050600082815261022c60205260408120555095945050505050565b600080608083901c1561546b57608092831c92015b604083901c1561547d57604092831c92015b602083901c1561548f57602092831c92015b601083901c156154a157601092831c92015b600883901c156154b357600892831c92015b600483901c156154c557600492831c92015b600283901c156154d757600292831c92015b600183901c15610f995760010192915050565b6000818310614fc65781612041565b600061550860028484186169ef565b61204190848416616baa565b8051600090603481101561552c576001915050610f99565b82810160131901516001600160a01b031981166b046e0e4dee0dee6cae47a60f60a31b1461555f57600192505050610f99565b60008061556d6028856169c6565b90505b838110156155e4576000806155a4888481518110615590576155906168ad565b01602001516001600160f81b0319166159a2565b91509150816155bc5760019650505050505050610f99565b8060ff166004856001600160a01b0316901b1793505050806155dd906168d9565b9050615570565b50856001600160a01b0316816001600160a01b031614935050505092915050565b60006001600160401b038211156139115760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610448565b600080615678613ce6565b80519091501561568f578051602090910120919050565b609854801561569e5792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b6000806156d1613cf5565b8051909150156156e8578051602090910120919050565b609954801561569e5792915050565b60008581526101c6602090815260408083206001600160a01b038816845260088101909252909120805460ff16156157875760405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20766f746560448201526c08185b1c9958591e4818d85cdd609a1b6064820152608401610448565b805460ff86166101000261ffff199091161760011781556157a784615a34565b81546001600160601b039190911662010000026dffffffffffffffffffffffff00001990911617815560ff85166157f757838260060160008282546157ec9190616baa565b909155506129fc9050565b60001960ff86160161581757838260050160008282546157ec9190616baa565b60011960ff86160161583757838260070160008282546157ec9190616baa565b60405162461bcd60e51b815260206004820152602d60248201527f476f7665726e6f72436f6d7061746962696c697479427261766f3a20696e766160448201526c6c696420766f7465207479706560981b6064820152608401610448565b6000806158a486868686612a05565b905060006158b182611751565b905060028160078111156158c7576158c76162c9565b141580156158e7575060068160078111156158e4576158e46162c9565b14155b801561590557506007816007811115615902576159026162c9565b14155b6159515760405162461bcd60e51b815260206004820152601d60248201527f476f7665726e6f723a2070726f706f73616c206e6f74206163746976650000006044820152606401610448565b6000828152610163602052604090819020600201805461ff001916610100179055517f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c906132109084815260200190565b60008060f883901c602f811180156159bd5750603a8160ff16105b156159d257600194602f199091019350915050565b8060ff1660401080156159e8575060478160ff16105b156159fd576001946036199091019350915050565b8060ff166060108015615a13575060678160ff16105b15615a28576001946056199091019350915050565b50600093849350915050565b60006001600160601b038211156139115760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b6064820152608401610448565b828054828255906000526020600020908101928215615af1579160200282015b82811115615af157825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615abc565b50613911929150615bdc565b828054828255906000526020600020908101928215615af1579160200282015b82811115615af1578251825591602001919060010190615b1d565b828054828255906000526020600020908101928215615b7e579160200282015b82811115615b7e5782518290615b6e9082616db6565b5091602001919060010190615b58565b50613911929150615bf1565b828054828255906000526020600020908101928215615bd0579160200282015b82811115615bd05782518290615bc09082616db6565b5091602001919060010190615baa565b50613911929150615c0e565b5b808211156139115760008155600101615bdd565b80821115613911576000615c058282615c2b565b50600101615bf1565b80821115613911576000615c228282615c2b565b50600101615c0e565b508054615c3790616873565b6000825580601f10615c47575050565b601f0160209004906000526020600020908101906111af9190615bdc565b600060208284031215615c7757600080fd5b5035919050565b600060208284031215615c9057600080fd5b81356001600160e01b03198116811461204157600080fd5b803560ff8116811461193957600080fd5b60008083601f840112615ccb57600080fd5b5081356001600160401b03811115615ce257600080fd5b602083019150836020828501011115615cfa57600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615d3f57615d3f615d01565b604052919050565b60006001600160401b03821115615d6057615d60615d01565b50601f01601f191660200190565b600082601f830112615d7f57600080fd5b8135615d92615d8d82615d47565b615d17565b818152846020838601011115615da757600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b031215615de057600080fd5b88359750615df060208a01615ca8565b965060408901356001600160401b0380821115615e0c57600080fd5b615e188c838d01615cb9565b909850965060608b0135915080821115615e3157600080fd5b50615e3e8b828c01615d6e565b945050615e4d60808a01615ca8565b925060a0890135915060c089013590509295985092959890939650565b60005b83811015615e85578181015183820152602001615e6d565b50506000910152565b60008151808452615ea6816020860160208601615e6a565b601f01601f19169290920160200192915050565b6020815260006120416020830184615e8e565b6001600160a01b03811681146111af57600080fd5b60008060008060808587031215615ef857600080fd5b8435615f0381615ecd565b93506020850135615f1381615ecd565b92506040850135915060608501356001600160401b03811115615f3557600080fd5b615f4187828801615d6e565b91505092959194509250565b60006001600160401b03821115615f6657615f66615d01565b5060051b60200190565b600082601f830112615f8157600080fd5b81356020615f91615d8d83615f4d565b82815260059290921b84018101918181019086841115615fb057600080fd5b8286015b84811015615fd4578035615fc781615ecd565b8352918301918301615fb4565b509695505050505050565b600082601f830112615ff057600080fd5b81356020616000615d8d83615f4d565b82815260059290921b8401810191818101908684111561601f57600080fd5b8286015b84811015615fd45780358352918301918301616023565b600082601f83011261604b57600080fd5b8135602061605b615d8d83615f4d565b82815260059290921b8401810191818101908684111561607a57600080fd5b8286015b84811015615fd45780356001600160401b0381111561609d5760008081fd5b6160ab8986838b0101615d6e565b84525091830191830161607e565b600080600080608085870312156160cf57600080fd5b84356001600160401b03808211156160e657600080fd5b6160f288838901615f70565b9550602087013591508082111561610857600080fd5b61611488838901615fdf565b9450604087013591508082111561612a57600080fd5b506161378782880161603a565b949793965093946060013593505050565b60006020828403121561615a57600080fd5b813561204181615ecd565b600081518084526020808501945080840160005b8381101561619e5781516001600160a01b031687529582019590820190600101616179565b509495945050505050565b600081518084526020808501945080840160005b8381101561619e578151875295820195908201906001016161bd565b600081518084526020808501808196508360051b8101915082860160005b8581101561622157828403895261620f848351615e8e565b988501989350908401906001016161f7565b5091979650505050505050565b6080815260006162416080830187616165565b828103602084015261625381876161a9565b9050828103604084015261626781866161d9565b9050828103606084015261174681856161d9565b600080600080600060a0868803121561629357600080fd5b853594506162a360208701615ca8565b93506162b160408701615ca8565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b602081016008831061630157634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561631a57600080fd5b82359150602083013561632c81615ecd565b809150509250929050565b6000806040838503121561634a57600080fd5b8235915061635a60208401615ca8565b90509250929050565b60008060008060006080868803121561637b57600080fd5b8535945061638b60208701615ca8565b935060408601356001600160401b03808211156163a757600080fd5b6163b389838a01615cb9565b909550935060608801359150808211156163cc57600080fd5b506163d988828901615d6e565b9150509295509295909350565b600080600080606085870312156163fc57600080fd5b8435935061640c60208601615ca8565b925060408501356001600160401b0381111561642757600080fd5b61643387828801615cb9565b95989497509550505050565b6000806000806080858703121561645557600080fd5b84356001600160401b038082111561646c57600080fd5b61647888838901615f70565b9550602087013591508082111561648e57600080fd5b61649a88838901615fdf565b945060408701359150808211156164b057600080fd5b6164bc8883890161603a565b935060608701359150808211156164d257600080fd5b50615f4187828801615d6e565b60ff60f81b8816815260e0602082015260006164fe60e0830189615e8e565b82810360408401526165108189615e8e565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152905061108981856161a9565b60008060006060848603121561655657600080fd5b833561656181615ecd565b92506020840135915060408401356001600160401b0381111561658357600080fd5b61658f86828701615d6e565b9150509250925092565b600080600080604085870312156165af57600080fd5b84356001600160401b03808211156165c657600080fd5b6165d288838901615cb9565b909650945060208701359150808211156165eb57600080fd5b5061643387828801615cb9565b600080600080600060a0868803121561661057600080fd5b853561661b81615ecd565b9450602086013561662b81615ecd565b935060408601356001600160401b038082111561664757600080fd5b61665389838a01615fdf565b9450606088013591508082111561666957600080fd5b61667589838a01615fdf565b935060808801359150808211156163cc57600080fd5b600080600080606085870312156166a157600080fd5b84356166ac81615ecd565b93506020850135925060408501356001600160401b0381111561642757600080fd5b6000602082840312156166e057600080fd5b81356001600160401b038116811461204157600080fd5b600080600080600060a0868803121561670f57600080fd5b85356001600160401b038082111561672657600080fd5b61673289838a01615f70565b9650602088013591508082111561674857600080fd5b61675489838a01615fdf565b9550604088013591508082111561676a57600080fd5b61677689838a0161603a565b9450606088013591508082111561678c57600080fd5b61667589838a0161603a565b600080604083850312156167ab57600080fd5b82356167b681615ecd565b946020939093013593505050565b600080600080600060a086880312156167dc57600080fd5b85356167e781615ecd565b945060208601356167f781615ecd565b9350604086013592506060860135915060808601356001600160401b0381111561682057600080fd5b6163d988828901615d6e565b8183823760009101908152919050565b60208082526018908201527f476f7665726e6f723a206f6e6c79476f7665726e616e63650000000000000000604082015260600190565b600181811c9082168061688757607f821691505b6020821081036168a757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016168eb576168eb6168c3565b5060010190565b65ffffffffffff828116828216039080821115616911576169116168c3565b5092915050565b60208082526021908201527f476f7665726e6f723a2070726f706f73616c206e6f74207375636365737366756040820152601b60fa1b606082015260800190565b60006020828403121561696b57600080fd5b81516001600160401b0381111561698157600080fd5b8201601f8101841361699257600080fd5b80516169a0615d8d82615d47565b8181528560208385010111156169b557600080fd5b611327826020830160208601615e6a565b81810381811115610f9957610f996168c3565b634e487b7160e01b600052601260045260246000fd5b600082616a0c57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215616a2357600080fd5b815165ffffffffffff8116811461204157600080fd5b600060208284031215616a4b57600080fd5b5051919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000616a8f604083018688616a52565b8281036020840152611746818587616a52565b608081526000616ab56080830187616165565b8281036020840152616ac781876161a9565b90508281036040840152616adb81866161d9565b91505082606083015295945050505050565b8082028115828204841417610f9957610f996168c3565b60a081526000616b1760a0830188616165565b8281036020840152616b2981886161a9565b90508281036040840152616b3d81876161d9565b60608401959095525050608001529392505050565b60c081526000616b6560c0830189616165565b8281036020840152616b7781896161a9565b90508281036040840152616b8b81886161d9565b60608401969096525050608081019290925260a0909101529392505050565b80820180821115610f9957610f996168c3565b600060208284031215616bcf57600080fd5b8151801515811461204157600080fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251616c3c818460208701615e6a565b9190910192915050565b6001600160e01b0319831681528151600090616c69816004850160208701615e6a565b919091016004019392505050565b6001600160401b03818116838216019080821115616911576169116168c3565b60208082526021908201527f476f7665726e6f723a20696e76616c69642070726f706f73616c206c656e67746040820152600d60fb1b606082015260800190565b8981526001600160a01b038916602082015261012060408201819052600090616d038382018b616165565b90508281036060840152616d17818a6161a9565b90508281036080840152616d2b81896161d9565b905082810360a0840152616d3f81886161d9565b90508560c08401528460e0840152828103610100840152616d608185615e8e565b9c9b505050505050505050505050565b601f821115613ba757600081815260208120601f850160051c81016020861015616d975750805b601f850160051c820191505b8181101561177f57828155600101616da3565b81516001600160401b03811115616dcf57616dcf615d01565b616de381616ddd8454616873565b84616d70565b602080601f831160018114616e185760008415616e005750858301515b600019600386901b1c1916600185901b17855561177f565b600085815260208120601f198616915b82811015616e4757888601518255948401946001909101908401616e28565b5085821015616e655787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b84815260ff84166020820152826040820152608060608201526000611b366080830184615e8e565b85815260ff8516602082015283604082015260a060608201526000616ec560a0830185615e8e565b8281036080840152611c4f8185615e8e56fe476f7665726e6f723a2072656c617920726576657274656420776974686f7574206d657373616765a164736f6c6343000811000a" + }, + "0x0000000000000000000000000000000000002005": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806370a082311161010f5780639ab24eb0116100a2578063d505accf11610071578063d505accf14610479578063dd62ed3e1461048c578063e5ed5b1e1461049f578063f1127ed8146104b257600080fd5b80639ab24eb01461042d578063a457c2d714610440578063a9059cbb14610453578063c3cda5201461046657600080fd5b806384b0196e116100de57806384b0196e146103d85780638e539e8c146103f357806391ddadf41461040657806395d89b411461042557600080fd5b806370a082311461038657806379cc6790146103af5780637ecebe00146103bd5780638129fc1c146103d057600080fd5b806339509351116101875780634bf5d7e9116101565780634bf5d7e9146102ff578063587cde1e146103075780635c19a95c1461034b5780636fcfff451461035e57600080fd5b806339509351146102b35780633a46b1a8146102c657806342966c68146102d957806344840775146102ec57600080fd5b806323b872dd116101c357806323b872dd146102745780633041949b14610287578063313ce5671461029c5780633644e515146102ab57600080fd5b8063039c91fc146101f557806306fdde0314610234578063095ea7b31461024957806318160ddd1461026c575b600080fd5b61022161020336600461209b565b61013060209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b61023c6104ef565b60405161022b9190612114565b61025c610257366004612127565b610581565b604051901515815260200161022b565b603554610221565b61025c610282366004612151565b61059b565b61029a61029536600461209b565b6105bf565b005b6040516012815260200161022b565b6102216105f8565b61025c6102c1366004612127565b610607565b6102216102d4366004612127565b610629565b61029a6102e736600461218d565b6106ae565b61029a6102fa3660046121a6565b6106c7565b61023c610740565b61033361031536600461222a565b6001600160a01b03908116600090815260fe60205260409020541690565b6040516001600160a01b03909116815260200161022b565b61029a61035936600461222a565b6107d8565b61037161036c36600461222a565b6107e5565b60405163ffffffff909116815260200161022b565b61022161039436600461222a565b6001600160a01b031660009081526033602052604090205490565b61029a6102e7366004612127565b6102216103cb36600461222a565b610807565b61029a610825565b6103e0610a05565b60405161022b9796959493929190612245565b61022161040136600461218d565b610aa3565b61040e610b0b565b60405165ffffffffffff909116815260200161022b565b61023c610b16565b61022161043b36600461222a565b610b25565b61025c61044e366004612127565b610ba7565b61025c610461366004612127565b610c22565b61029a6104743660046122ec565b610c30565b61029a610487366004612344565b610d66565b61022161049a36600461209b565b610eca565b61029a6104ad36600461209b565b610ef5565b6104c56104c03660046123ae565b610f25565b60408051825163ffffffff1681526020928301516001600160e01b0316928101929092520161022b565b6060603680546104fe906123ee565b80601f016020809104026020016040519081016040528092919081815260200182805461052a906123ee565b80156105775780601f1061054c57610100808354040283529160200191610577565b820191906000526020600020905b81548152906001019060200180831161055a57829003601f168201915b5050505050905090565b60003361058f818585610fa9565b60019150505b92915050565b6000336105a9858285610fc2565b6105b485858561103c565b506001949350505050565b33612002146105ea57604051630f22c43960e41b815261200260048201526024015b60405180910390fd5b6105f48282611055565b5050565b6000610602611185565b905090565b60003361058f81858561061a8383610eca565b6106249190612438565b610fa9565b6000610633610b0b565b65ffffffffffff1682106106855760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b60448201526064016105e1565b6001600160a01b038316600090815260ff602052604090206106a7908361118f565b9392505050565b60405163e5d8776760e01b815260040160405180910390fd5b33612002146106ed57604051630f22c43960e41b815261200260048201526024016105e1565b8160005b818110156107395761072985858381811061070e5761070e61244b565b9050602002016020810190610723919061222a565b84611055565b61073281612461565b90506106f1565b5050505050565b60604361074b610b0b565b65ffffffffffff16146107a05760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a2062726f6b656e20636c6f636b206d6f646500000060448201526064016105e1565b5060408051808201909152601d81527f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b6107e23382611278565b50565b6001600160a01b038116600090815260ff6020526040812054610595906112f2565b6001600160a01b038116600090815260cb6020526040812054610595565b600054610100900460ff16158080156108455750600054600160ff909116105b8061085f5750303b15801561085f575060005460ff166001145b6108c25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105e1565b6000805460ff1916600117905580156108e5576000805461ff0019166101001790555b3341146109055760405163022d8c9560e31b815260040160405180910390fd5b3a15610924576040516383f1b1d360e01b815260040160405180910390fd5b610978604051806040016040528060148152602001732129a19023b7bb32b93730b731b2902a37b5b2b760611b8152506040518060400160405280600681526020016533b7bb21272160d11b81525061135b565b61098061138c565b6109b5604051806040016040528060148152602001732129a19023b7bb32b93730b731b2902a37b5b2b760611b8152506113b5565b6109bd61138c565b80156107e2576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000606080600080600060606097546000801b148015610a255750609854155b610a695760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064016105e1565b610a716113ff565b610a7961140e565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b6000610aad610b0b565b65ffffffffffff168210610aff5760405162461bcd60e51b815260206004820152601960248201527804552433230566f7465733a20667574757265206c6f6f6b757603c1b60448201526064016105e1565b6105956101008361118f565b60006106024361141d565b6060603780546104fe906123ee565b6001600160a01b038116600090815260ff60205260408120548015610b94576001600160a01b038316600090815260ff6020526040902080546000198301908110610b7257610b7261244b565b60009182526020909120015464010000000090046001600160e01b0316610b97565b60005b6001600160e01b03169392505050565b60003381610bb58286610eca565b905083811015610c155760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016105e1565b6105b48286868403610fa9565b60003361058f81858561103c565b83421115610c805760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e6174757265206578706972656400000060448201526064016105e1565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610cfa90610cf29060a00160405160208183030381529060405280519060200120611484565b8585856114b1565b9050610d05816114d9565b8614610d535760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e63650000000000000060448201526064016105e1565b610d5d8188611278565b50505050505050565b83421115610db65760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016105e1565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610de58c6114d9565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610e4082611484565b90506000610e50828787876114b1565b9050896001600160a01b0316816001600160a01b031614610eb35760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016105e1565b610ebe8a8a8a610fa9565b50505050505050505050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b3361200214610f1b57604051630f22c43960e41b815261200260048201526024016105e1565b6105f48282611278565b60408051808201909152600080825260208201526001600160a01b038316600090815260ff60205260409020805463ffffffff8416908110610f6957610f6961244b565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b604051632028747160e01b815260040160405180910390fd5b6000610fce8484610eca565b9050600019811461103657818110156110295760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016105e1565b6110368484848403610fa9565b50505050565b604051638cd22d1960e01b815260040160405180910390fd5b604051630913db4760e01b81526001600160a01b03828116600483015260009190841690630913db4790602401602060405180830381865afa15801561109f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c39190612490565b6001600160a01b03808516600090815261013060209081526040808320938716835292905220549091508181101561113c57600061110182846124a9565b6001600160a01b0380871660009081526101306020908152604080832093891683529290522084905590506111368482611501565b50611036565b8181111561103657600061115083836124a9565b6001600160a01b038087166000908152610130602090815260408083209389168352929052208490559050610739848261150b565b6000610602611515565b8154600090818160058111156111e95760006111aa84611589565b6111b490856124a9565b600088815260209020909150869082015463ffffffff1611156111d9578091506111e7565b6111e4816001612438565b92505b505b808210156112365760006111fd8383611671565b600088815260209020909150869082015463ffffffff16111561122257809150611230565b61122d816001612438565b92505b506111e9565b8015611262576000868152602090208101600019015464010000000090046001600160e01b0316611265565b60005b6001600160e01b03169695505050505050565b6001600160a01b03828116600081815260fe6020818152604080842080546033845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a461103682848361168c565b600063ffffffff8211156113575760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016105e1565b5090565b600054610100900460ff166113825760405162461bcd60e51b81526004016105e1906124bc565b6105f482826117ca565b600054610100900460ff166113b35760405162461bcd60e51b81526004016105e1906124bc565b565b600054610100900460ff166113dc5760405162461bcd60e51b81526004016105e1906124bc565b6107e281604051806040016040528060018152602001603160f81b81525061180a565b6060609980546104fe906123ee565b6060609a80546104fe906123ee565b600065ffffffffffff8211156113575760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203460448201526538206269747360d01b60648201526084016105e1565b6000610595611491611185565b8360405161190160f01b8152600281019290925260228201526042902090565b60008060006114c287878787611859565b915091506114cf8161191d565b5095945050505050565b6001600160a01b038116600090815260cb602052604090208054600181018255905b50919050565b6105f48282611a67565b6105f48282611af2565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611540611b0b565b611548611b64565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008160000361159b57506000919050565b600060016115a884611b95565b901c6001901b905060018184816115c1576115c1612507565b048201901c905060018184816115d9576115d9612507565b048201901c905060018184816115f1576115f1612507565b048201901c9050600181848161160957611609612507565b048201901c9050600181848161162157611621612507565b048201901c9050600181848161163957611639612507565b048201901c9050600181848161165157611651612507565b048201901c90506106a78182858161166b5761166b612507565b04611c29565b6000611680600284841861251d565b6106a790848416612438565b816001600160a01b0316836001600160a01b0316141580156116ae5750600081115b156117c5576001600160a01b0383161561173c576001600160a01b038316600090815260ff6020526040812081906116e990611c3f85611c4b565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611731929190918252602082015260400190565b60405180910390a250505b6001600160a01b038216156117c5576001600160a01b038216600090815260ff60205260408120819061177290611dc085611c4b565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516117ba929190918252602082015260400190565b60405180910390a250505b505050565b600054610100900460ff166117f15760405162461bcd60e51b81526004016105e1906124bc565b60366117fd838261258d565b5060376117c5828261258d565b600054610100900460ff166118315760405162461bcd60e51b81526004016105e1906124bc565b609961183d838261258d565b50609a61184a828261258d565b50506000609781905560985550565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156118905750600090506003611914565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156118e4573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661190d57600060019250925050611914565b9150600090505b94509492505050565b60008160048111156119315761193161264d565b036119395750565b600181600481111561194d5761194d61264d565b0361199a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105e1565b60028160048111156119ae576119ae61264d565b036119fb5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105e1565b6003816004811115611a0f57611a0f61264d565b036107e25760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105e1565b611a718282611dcc565b6035546001600160e01b031015611ae35760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b60648201526084016105e1565b611036610100611dc083611c4b565b611afc8282611e95565b611036610100611c3f83611c4b565b600080611b166113ff565b805190915015611b2d578051602090910120919050565b6097548015611b3c5792915050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4709250505090565b600080611b6f61140e565b805190915015611b86578051602090910120919050565b6098548015611b3c5792915050565b600080608083901c15611baa57608092831c92015b604083901c15611bbc57604092831c92015b602083901c15611bce57602092831c92015b601083901c15611be057601092831c92015b600883901c15611bf257600892831c92015b600483901c15611c0457600492831c92015b600283901c15611c1657600292831c92015b600183901c156105955760010192915050565b6000818310611c3857816106a7565b5090919050565b60006106a782846124a9565b82546000908190818115611c985760008781526020902082016000190160408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152611cad565b60408051808201909152600080825260208201525b905080602001516001600160e01b03169350611ccd84868863ffffffff16565b9250600082118015611cf75750611ce2610b0b565b65ffffffffffff16816000015163ffffffff16145b15611d3c57611d0583611fd0565b60008881526020902083016000190180546001600160e01b03929092166401000000000263ffffffff909216919091179055611db6565b866040518060400160405280611d60611d53610b0b565b65ffffffffffff166112f2565b63ffffffff168152602001611d7486611fd0565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b60006106a78284612438565b6001600160a01b038216611e225760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016105e1565b8060356000828254611e349190612438565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36105f460008383612039565b6001600160a01b038216611ef55760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016105e1565b6001600160a01b03821660009081526033602052604090205481811015611f695760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016105e1565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36117c583600084612039565b60006001600160e01b038211156113575760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b60648201526084016105e1565b6117c58383836001600160a01b03808416600090815260fe60205260409020546117c591166001600160a01b03808516600090815260fe6020526040902054168361168c565b80356001600160a01b038116811461209657600080fd5b919050565b600080604083850312156120ae57600080fd5b6120b78361207f565b91506120c56020840161207f565b90509250929050565b6000815180845260005b818110156120f4576020818501810151868301820152016120d8565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006106a760208301846120ce565b6000806040838503121561213a57600080fd5b6121438361207f565b946020939093013593505050565b60008060006060848603121561216657600080fd5b61216f8461207f565b925061217d6020850161207f565b9150604084013590509250925092565b60006020828403121561219f57600080fd5b5035919050565b6000806000604084860312156121bb57600080fd5b833567ffffffffffffffff808211156121d357600080fd5b818601915086601f8301126121e757600080fd5b8135818111156121f657600080fd5b8760208260051b850101111561220b57600080fd5b602092830195509350612221918601905061207f565b90509250925092565b60006020828403121561223c57600080fd5b6106a78261207f565b60ff60f81b881681526000602060e08184015261226560e084018a6120ce565b8381036040850152612277818a6120ce565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156122c9578351835292840192918401916001016122ad565b50909c9b505050505050505050505050565b803560ff8116811461209657600080fd5b60008060008060008060c0878903121561230557600080fd5b61230e8761207f565b9550602087013594506040870135935061232a606088016122db565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a03121561235f57600080fd5b6123688861207f565b96506123766020890161207f565b95506040880135945060608801359350612392608089016122db565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156123c157600080fd5b6123ca8361207f565b9150602083013563ffffffff811681146123e357600080fd5b809150509250929050565b600181811c9082168061240257607f821691505b6020821081036114fb57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561059557610595612422565b634e487b7160e01b600052603260045260246000fd5b60006001820161247357612473612422565b5060010190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156124a257600080fd5b5051919050565b8181038181111561059557610595612422565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b60008261253a57634e487b7160e01b600052601260045260246000fd5b500490565b601f8211156117c557600081815260208120601f850160051c810160208610156125665750805b601f850160051c820191505b8181101561258557828155600101612572565b505050505050565b815167ffffffffffffffff8111156125a7576125a761247a565b6125bb816125b584546123ee565b8461253f565b602080601f8311600181146125f057600084156125d85750858301515b600019600386901b1c1916600185901b178555612585565b600085815260208120601f198616915b8281101561261f57888601518255948401946001909101908401612600565b508582101561263d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052602160045260246000fdfea164736f6c6343000811000a" + }, + "0x0000000000000000000000000000000000002006": { + "balance": "0x0", + "code": "0x6080604052600436106101d15760003560e01c80638129fc1c116100f7578063b1c5f42711610095578063d547741f11610064578063d547741f14610584578063e38335e5146105a4578063f23a6e61146105b7578063f27a0c92146105e357600080fd5b8063b1c5f427146104eb578063bc197c811461050b578063c4d252f514610537578063d45c44351461055757600080fd5b806391d14854116100d157806391d1485414610474578063a217fddf14610494578063ac431751146104a9578063b08e51c0146104c957600080fd5b80638129fc1c1461041d5780638f2a0bb0146104325780638f61f4f51461045257600080fd5b8063248a9ca31161016f57806336568abe1161013e57806336568abe1461039d578063584b153e146103bd57806364d62353146103dd5780638065657f146103fd57600080fd5b8063248a9ca3146102fd5780632ab0f5291461032d5780632f2ff15d1461035d57806331d507501461037d57600080fd5b80630d3cf6fc116101ab5780630d3cf6fc14610264578063134008d31461028657806313bc9f2014610299578063150b7a02146102b957600080fd5b806301d5062a146101dd57806301ffc9a7146101ff57806307bd02651461023457600080fd5b366101d857005b600080fd5b3480156101e957600080fd5b506101fd6101f8366004611a52565b6105f8565b005b34801561020b57600080fd5b5061021f61021a366004611ac6565b6106bc565b60405190151581526020015b60405180910390f35b34801561024057600080fd5b5061025660008051602061253983398151915281565b60405190815260200161022b565b34801561027057600080fd5b506102566000805160206124f983398151915281565b6101fd610294366004611af0565b6106e7565b3480156102a557600080fd5b5061021f6102b4366004611b5b565b61078a565b3480156102c557600080fd5b506102e46102d4366004611c29565b630a85bd0160e11b949350505050565b6040516001600160e01b0319909116815260200161022b565b34801561030957600080fd5b50610256610318366004611b5b565b60009081526065602052604090206001015490565b34801561033957600080fd5b5061021f610348366004611b5b565b60009081526097602052604090205460011490565b34801561036957600080fd5b506101fd610378366004611c90565b6107b0565b34801561038957600080fd5b5061021f610398366004611b5b565b6107da565b3480156103a957600080fd5b506101fd6103b8366004611c90565b6107f3565b3480156103c957600080fd5b5061021f6103d8366004611b5b565b610876565b3480156103e957600080fd5b506101fd6103f8366004611b5b565b61088d565b34801561040957600080fd5b50610256610418366004611af0565b610931565b34801561042957600080fd5b506101fd610970565b34801561043e57600080fd5b506101fd61044d366004611d00565b610b20565b34801561045e57600080fd5b5061025660008051602061251983398151915281565b34801561048057600080fd5b5061021f61048f366004611c90565b610ca1565b3480156104a057600080fd5b50610256600081565b3480156104b557600080fd5b506101fd6104c4366004611db1565b610ccc565b3480156104d557600080fd5b5061025660008051602061255983398151915281565b3480156104f757600080fd5b50610256610506366004611e1c565b610eb6565b34801561051757600080fd5b506102e4610526366004611f43565b63bc197c8160e01b95945050505050565b34801561054357600080fd5b506101fd610552366004611b5b565b610efb565b34801561056357600080fd5b50610256610572366004611b5b565b60009081526097602052604090205490565b34801561059057600080fd5b506101fd61059f366004611c90565b610fbe565b6101fd6105b2366004611e1c565b610fe3565b3480156105c357600080fd5b506102e46105d2366004611fec565b63f23a6e6160e01b95945050505050565b3480156105ef57600080fd5b50609854610256565b6000805160206125198339815191526106108161115b565b6000610620898989898989610931565b905061062c8184611165565b6000817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161066896959493929190612079565b60405180910390a383156106b157807f20fda5fd27a1ea7bf5b9567f143ac5470bb059374a27e8f67cb44f946f6d0387856040516106a891815260200190565b60405180910390a25b505050505050505050565b60006001600160e01b03198216630271189760e51b14806106e157506106e182611254565b92915050565b600080516020612539833981519152610701816000610ca1565b61070f5761070f8133611289565b600061071f888888888888610931565b905061072b81856112e2565b6107378888888861137d565b6000817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161076f94939291906120b6565b60405180910390a361078081611450565b5050505050505050565b6000818152609760205260408120546001811180156107a95750428111155b9392505050565b6000828152606560205260409020600101546107cb8161115b565b6107d58383611489565b505050565b60008181526097602052604081205481905b1192915050565b6001600160a01b03811633146108685760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610872828261150f565b5050565b6000818152609760205260408120546001906107ec565b3330146108f05760405162461bcd60e51b815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201526a62652074696d656c6f636b60a81b606482015260840161085f565b60985460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1609855565b600086868686868660405160200161094e96959493929190612079565b6040516020818303038152906040528051906020012090509695505050505050565b600054610100900460ff16158080156109905750600054600160ff909116105b806109aa5750303b1580156109aa575060005460ff166001145b610a0d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161085f565b6000805460ff191660011790558015610a30576000805461ff0019166101001790555b334114610a505760405163022d8c9560e31b815260040160405180910390fd5b3a15610a6f576040516383f1b1d360e01b815260040160405180910390fd5b6040805160018082528183019092526000916020808301908036833701905050905061200481600081518110610aa757610aa76120e8565b60200260200101906001600160a01b031690816001600160a01b031681525050610ad6603c8283612004611576565b508015610b1d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b600080516020612519833981519152610b388161115b565b888714610b575760405162461bcd60e51b815260040161085f906120fe565b888514610b765760405162461bcd60e51b815260040161085f906120fe565b6000610b888b8b8b8b8b8b8b8b610eb6565b9050610b948184611165565b60005b8a811015610c525780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610bd457610bd46120e8565b9050602002016020810190610be99190612141565b8d8d86818110610bfb57610bfb6120e8565b905060200201358c8c87818110610c1457610c146120e8565b9050602002810190610c26919061215c565b8c8b604051610c3a96959493929190612079565b60405180910390a3610c4b816121b8565b9050610b97565b508315610c9457807f20fda5fd27a1ea7bf5b9567f143ac5470bb059374a27e8f67cb44f946f6d038785604051610c8b91815260200190565b60405180910390a25b5050505050505050505050565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3361100714610cf257604051630f22c43960e41b8152611007600482015260240161085f565b610d55604051806040016040528060088152602001676d696e44656c617960c01b81525085858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092939250506115af9050565b15610e525760208114610d835783838383604051630a5a604160e01b815260040161085f94939291906121d1565b604080516020601f8401819004810282018101909252828152600091610dc49185858083850183828082843760009201919091525092939250506116089050565b9050801580610dd557506212750081115b15610dfb5784848484604051630a5a604160e01b815260040161085f94939291906121d1565b6040516364d6235360e01b81526004810182905230906364d6235390602401600060405180830381600087803b158015610e3457600080fd5b505af1158015610e48573d6000803e3d6000fd5b5050505050610e73565b838383836040516325ee20d560e21b815260040161085f94939291906121d1565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e63384848484604051610ea894939291906121d1565b60405180910390a150505050565b60008888888888888888604051602001610ed7989796959493929190612289565b60405160208183030381529060405280519060200120905098975050505050505050565b600080516020612559833981519152610f138161115b565b610f1c82610876565b610f825760405162461bcd60e51b815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e2063616044820152701b9b9bdd0818994818d85b98d95b1b1959607a1b606482015260840161085f565b6000828152609760205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b600082815260656020526040902060010154610fd98161115b565b6107d5838361150f565b600080516020612539833981519152610ffd816000610ca1565b61100b5761100b8133611289565b87861461102a5760405162461bcd60e51b815260040161085f906120fe565b8784146110495760405162461bcd60e51b815260040161085f906120fe565b600061105b8a8a8a8a8a8a8a8a610eb6565b905061106781856112e2565b60005b898110156111455760008b8b83818110611086576110866120e8565b905060200201602081019061109b9190612141565b905060008a8a848181106110b1576110b16120e8565b9050602002013590503660008a8a868181106110cf576110cf6120e8565b90506020028101906110e1919061215c565b915091506110f18484848461137d565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588686868660405161112894939291906120b6565b60405180910390a3505050508061113e906121b8565b905061106a565b5061114f81611450565b50505050505050505050565b610b1d8133611289565b61116e826107da565b156111d35760405162461bcd60e51b815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201526e1c9958591e481cd8da19591d5b1959608a1b606482015260840161085f565b6098548110156112345760405162461bcd60e51b815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e746044820152652064656c617960d01b606482015260840161085f565b61123e814261232a565b6000928352609760205260409092209190915550565b60006001600160e01b03198216637965db0b60e01b14806106e157506301ffc9a760e01b6001600160e01b03198316146106e1565b6112938282610ca1565b610872576112a08161160d565b6112ab83602061161f565b6040516020016112bc929190612361565b60408051601f198184030181529082905262461bcd60e51b825261085f916004016123d6565b6112eb8261078a565b6113075760405162461bcd60e51b815260040161085f90612409565b80158061132257506000818152609760205260409020546001145b6108725760405162461bcd60e51b815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e6720646570656044820152656e64656e637960d01b606482015260840161085f565b6000846001600160a01b031684848460405161139a929190612453565b60006040518083038185875af1925050503d80600081146113d7576040519150601f19603f3d011682016040523d82523d6000602084013e6113dc565b606091505b50509050806114495760405162461bcd60e51b815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e6720746044820152721c985b9cd858dd1a5bdb881c995d995c9d1959606a1b606482015260840161085f565b5050505050565b6114598161078a565b6114755760405162461bcd60e51b815260040161085f90612409565b600090815260976020526040902060019055565b6114938282610ca1565b6108725760008281526065602090815260408083206001600160a01b03851684529091529020805460ff191660011790556114cb3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6115198282610ca1565b156108725760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b600054610100900460ff1661159d5760405162461bcd60e51b815260040161085f90612463565b6115a9848484846117ba565b50505050565b6000816040516020016115c291906124ae565b60405160208183030381529060405280519060200120836040516020016115e991906124ae565b6040516020818303038152906040528051906020012014905092915050565b015190565b60606106e16001600160a01b03831660145b6060600061162e8360026124ca565b61163990600261232a565b6001600160401b0381111561165057611650611b74565b6040519080825280601f01601f19166020018201604052801561167a576020820181803683370190505b509050600360fc1b81600081518110611695576116956120e8565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106116c4576116c46120e8565b60200101906001600160f81b031916908160001a90535060006116e88460026124ca565b6116f390600161232a565b90505b600181111561176b576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611727576117276120e8565b1a60f81b82828151811061173d5761173d6120e8565b60200101906001600160f81b031916908160001a90535060049490941c93611764816124e1565b90506116f6565b5083156107a95760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161085f565b600054610100900460ff166117e15760405162461bcd60e51b815260040161085f90612463565b6117f96000805160206124f983398151915280611999565b61181f6000805160206125198339815191526000805160206124f9833981519152611999565b6118456000805160206125398339815191526000805160206124f9833981519152611999565b61186b6000805160206125598339815191526000805160206124f9833981519152611999565b6118836000805160206124f9833981519152306119e4565b6001600160a01b038116156118aa576118aa6000805160206124f9833981519152826119e4565b60005b835181101561191b576118e76000805160206125198339815191528583815181106118da576118da6120e8565b60200260200101516119e4565b61190b6000805160206125598339815191528583815181106118da576118da6120e8565b611914816121b8565b90506118ad565b5060005b825181101561195c5761194c6000805160206125398339815191528483815181106118da576118da6120e8565b611955816121b8565b905061191f565b5060988490556040805160008152602081018690527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d59101610ea8565b600082815260656020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6108728282611489565b80356001600160a01b0381168114611a0557600080fd5b919050565b60008083601f840112611a1c57600080fd5b5081356001600160401b03811115611a3357600080fd5b602083019150836020828501011115611a4b57600080fd5b9250929050565b600080600080600080600060c0888a031215611a6d57600080fd5b611a76886119ee565b96506020880135955060408801356001600160401b03811115611a9857600080fd5b611aa48a828b01611a0a565b989b979a50986060810135976080820135975060a09091013595509350505050565b600060208284031215611ad857600080fd5b81356001600160e01b0319811681146107a957600080fd5b60008060008060008060a08789031215611b0957600080fd5b611b12876119ee565b95506020870135945060408701356001600160401b03811115611b3457600080fd5b611b4089828a01611a0a565b979a9699509760608101359660809091013595509350505050565b600060208284031215611b6d57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611bb257611bb2611b74565b604052919050565b600082601f830112611bcb57600080fd5b81356001600160401b03811115611be457611be4611b74565b611bf7601f8201601f1916602001611b8a565b818152846020838601011115611c0c57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215611c3f57600080fd5b611c48856119ee565b9350611c56602086016119ee565b92506040850135915060608501356001600160401b03811115611c7857600080fd5b611c8487828801611bba565b91505092959194509250565b60008060408385031215611ca357600080fd5b82359150611cb3602084016119ee565b90509250929050565b60008083601f840112611cce57600080fd5b5081356001600160401b03811115611ce557600080fd5b6020830191508360208260051b8501011115611a4b57600080fd5b600080600080600080600080600060c08a8c031215611d1e57600080fd5b89356001600160401b0380821115611d3557600080fd5b611d418d838e01611cbc565b909b50995060208c0135915080821115611d5a57600080fd5b611d668d838e01611cbc565b909950975060408c0135915080821115611d7f57600080fd5b50611d8c8c828d01611cbc565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b60008060008060408587031215611dc757600080fd5b84356001600160401b0380821115611dde57600080fd5b611dea88838901611a0a565b90965094506020870135915080821115611e0357600080fd5b50611e1087828801611a0a565b95989497509550505050565b60008060008060008060008060a0898b031215611e3857600080fd5b88356001600160401b0380821115611e4f57600080fd5b611e5b8c838d01611cbc565b909a50985060208b0135915080821115611e7457600080fd5b611e808c838d01611cbc565b909850965060408b0135915080821115611e9957600080fd5b50611ea68b828c01611cbc565b999c989b509699959896976060870135966080013595509350505050565b600082601f830112611ed557600080fd5b813560206001600160401b03821115611ef057611ef0611b74565b8160051b611eff828201611b8a565b9283528481018201928281019087851115611f1957600080fd5b83870192505b84831015611f3857823582529183019190830190611f1f565b979650505050505050565b600080600080600060a08688031215611f5b57600080fd5b611f64866119ee565b9450611f72602087016119ee565b935060408601356001600160401b0380821115611f8e57600080fd5b611f9a89838a01611ec4565b94506060880135915080821115611fb057600080fd5b611fbc89838a01611ec4565b93506080880135915080821115611fd257600080fd5b50611fdf88828901611bba565b9150509295509295909350565b600080600080600060a0868803121561200457600080fd5b61200d866119ee565b945061201b602087016119ee565b9350604086013592506060860135915060808601356001600160401b0381111561204457600080fd5b611fdf88828901611bba565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60018060a01b038716815285602082015260a0604082015260006120a160a083018688612050565b60608301949094525060800152949350505050565b60018060a01b03851681528360208201526060604082015260006120de606083018486612050565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b60208082526023908201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d616040820152620e8c6d60eb1b606082015260800190565b60006020828403121561215357600080fd5b6107a9826119ee565b6000808335601e1984360301811261217357600080fd5b8301803591506001600160401b0382111561218d57600080fd5b602001915036819003821315611a4b57600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016121ca576121ca6121a2565b5060010190565b6040815260006121e5604083018688612050565b8281036020840152611f38818587612050565b81835260006020808501808196508560051b810191508460005b8781101561227c5782840389528135601e1988360301811261223357600080fd5b870185810190356001600160401b0381111561224e57600080fd5b80360382131561225d57600080fd5b612268868284612050565b9a87019a9550505090840190600101612212565b5091979650505050505050565b60a0808252810188905260008960c08301825b8b8110156122ca576001600160a01b036122b5846119ee565b1682526020928301929091019060010161229c565b5083810360208501528881526001600160fb1b038911156122ea57600080fd5b8860051b9150818a6020830137018281036020908101604085015261231290820187896121f8565b60608401959095525050608001529695505050505050565b808201808211156106e1576106e16121a2565b60005b83811015612358578181015183820152602001612340565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161239981601785016020880161233d565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516123ca81602884016020880161233d565b01602801949350505050565b60208152600082518060208401526123f581604085016020870161233d565b601f01601f19169190910160400192915050565b6020808252602a908201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e206973604082015269206e6f7420726561647960b01b606082015260800190565b8183823760009101908152919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082516124c081846020870161233d565b9190910192915050565b80820281158282048414176106e1576106e16121a2565b6000816124f0576124f06121a2565b50600019019056fe5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5b09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1d8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63fd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783a164736f6c6343000811000a" + }, + "0x0000000000000000000000000000000000003000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101005760003560e01c80638456cb5911610097578063bfb5a6a111610066578063bfb5a6a114610212578063dd42a1dd14610225578063e33f8d321461024f578063e842426a1461027257600080fd5b80638456cb59146101df5780639fcb5012146101e7578063ac431751146101f4578063b187bd261461020757600080fd5b80634a49ac4c116100d35780634a49ac4c14610171578063572c99801461018457806374be2150146101975780638129fc1c146101d757600080fd5b8063046f7da2146101055780632eb4a7ab1461010f578063417c73a71461012b5780634838d1651461013e575b600080fd5b61010d610285565b005b61011860685481565b6040519081526020015b60405180910390f35b61010d61013936600461168d565b61030d565b61016161014c36600461168d565b60346020526000908152604090205460ff1681565b6040519015158152602001610122565b61010d61017f36600461168d565b610389565b61010d6101923660046116a8565b610402565b6101ca6040518060400160405280601481526020017342696e616e63652d436861696e2d47616e67657360601b81525081565b6040516101229190611724565b61010d610498565b61010d61060a565b6069546101619060ff1681565b61010d610202366004611780565b610696565b60335460ff16610161565b61010d610220366004611831565b610ab5565b60335461010090046001600160a01b03165b6040516001600160a01b039091168152602001610122565b61016161025d36600461190b565b6000908152606a602052604090205460ff1690565b606754610237906001600160a01b031681565b60335461010090046001600160a01b031633146102b5576040516306fbb1e360e01b815260040160405180910390fd5b60335460ff166102d857604051636cd6020160e01b815260040160405180910390fd5b6033805460ff191690556040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f990600090a1565b60335461010090046001600160a01b0316331461033d576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260346020526040808220805460ff19166001179055517f7fd26be6fc92aff63f1f4409b2b2ddeb272a888031d7f55ec830485ec61941869190a250565b60335461010090046001600160a01b031633146103b9576040516306fbb1e360e01b815260040160405180910390fd5b6001600160a01b038116600081815260346020526040808220805460ff19169055517fe0db3499b7fdc3da4cddff5f45d694549c19835e7f719fb5606d3ad1a5de40119190a250565b60335461010090046001600160a01b03163314610432576040516306fbb1e360e01b815260040160405180910390fd5b604051638525db0360e01b8152600481018390526001600160a01b038216602482015261100490638525db0390604401600060405180830381600087803b15801561047c57600080fd5b505af1158015610490573d6000803e3d6000fd5b505050505050565b600054610100900460ff16158080156104b85750600054600160ff909116105b806104d25750303b1580156104d2575060005460ff166001145b61053a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561055d576000805461ff0019166101001790555b33411461057d5760405163022d8c9560e31b815260040160405180910390fd5b3a1561059c576040516383f1b1d360e01b815260040160405180910390fd5b6105a4610e15565b6105c17304d63abcd2b9b1baa327f2dda0f873f197ccd186610e42565b8015610607576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b60335461010090046001600160a01b0316331461063a576040516306fbb1e360e01b815260040160405180910390fd5b60335460ff161561065e57604051631785c68160e01b815260040160405180910390fd5b6033805460ff191660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b33611007146106bc57604051630f22c43960e41b81526110076004820152602401610531565b6107266040518060400160405280600f81526020016e617070726f76616c4164647265737360881b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050610e919050565b156107f057601481146107545783838383604051630a5a604160e01b8152600401610531949392919061194d565b600061079a601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050610eeb9050565b90506001600160a01b0381166107cb5784848484604051630a5a604160e01b8152600401610531949392919061194d565b606780546001600160a01b0319166001600160a01b0392909216919091179055610a72565b6108556040518060400160405280600a8152602001691b595c9adb19549bdbdd60b21b81525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050610e919050565b156109255760695460ff161561087e576040516379b3306f60e11b815260040160405180910390fd5b602081146108a75783838383604051630a5a604160e01b8152600401610531949392919061194d565b604080516020601f84018190048102820181019092528281526000916108e8918585808385018382808284376000920191909152509293925050610eeb9050565b9050806109105784848484604051630a5a604160e01b8152600401610531949392919061194d565b6068556069805460ff19166001179055610a72565b61099d6040518060400160405280601b81526020017f746f6b656e5265636f766572506f7274616c50726f746563746f72000000000081525085858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050610e919050565b15610a5157601481146109cb5783838383604051630a5a604160e01b8152600401610531949392919061194d565b6000610a11601484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050610eeb9050565b90506001600160a01b038116610a425784848484604051630a5a604160e01b8152600401610531949392919061194d565b610a4b81610ef0565b50610a72565b838383836040516325ee20d560e21b8152600401610531949392919061194d565b7ff1ce9b2cbf50eeb05769a29e2543fd350cab46894a7dd9978a12d534bb20e63384848484604051610aa7949392919061194d565b60405180910390a150505050565b60695460ff16610ad85760405163678f619760e11b815260040160405180910390fd5b606854610af85760405163678f619760e11b815260040160405180910390fd5b6067546001600160a01b0316610b2157604051631a1b977b60e31b815260040160405180910390fd5b60335460ff1615610b4557604051631785c68160e01b815260040160405180910390fd5b610b4d610f57565b6000610bdb89898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a9081908401838280828437600081840152601f19601f82011690508083019250505050505050610bd68e8e33610fb0565b6110d1565b90506000818c8c604051602001610bf49392919061197f565b604051602081830303815290604052805190602001209050610c25816000908152606a602052604090205460ff1690565b15610c4257604051623e493160e81b815260040160405180910390fd5b610cea3389898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a908190840183828082843760009201919091525050604080516020808c0282810182019093528b82528994509092508b918b918291908501908490808284376000920191909152506111a992505050565b610d2b8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060685491508490506112b4565b610d48576040516309bde33960e01b815260040160405180910390fd5b6000818152606a602052604090819020805460ff191660011790555163799758b960e01b8152600481018d9052336024820152604481018c90526110049063799758b990606401600060405180830381600087803b158015610da957600080fd5b505af1158015610dbd573d6000803e3d6000fd5b505050507f39cc0b7297a0ef9102d75ebc4919ffec0347d50008c2b865eda4125d5812cb64828d338e604051610df694939291906119a6565b60405180910390a15050610e0960018055565b50505050505050505050565b600054610100900460ff16610e3c5760405162461bcd60e51b8152600401610531906119de565b60018055565b600054610100900460ff16610e695760405162461bcd60e51b8152600401610531906119de565b603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600081604051602001610ea49190611a29565b6040516020818303038152906040528051906020012083604051602001610ecb9190611a29565b604051602081830303815290604052805190602001201490505b92915050565b015190565b6033546040516001600160a01b0380841692610100900416907f44fc1b38a4abaa91ebd1b628a5b259a698f86238c8217d68f516e87769c60c0b90600090a3603380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600260015403610fa95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610531565b6002600155565b600060026040518060400160405280601481526020017342696e616e63652d436861696e2d47616e67657360601b81525061100d85604051602001610ff791815260200190565b60405160208183030381529060405260006112ca565b6040516bffffffffffffffffffffffff19606087901b1660208201526110469060340160405160208183030381529060405260016112ca565b61105c88604051602001610ff791815260200190565b60405160200161106f9493929190611a45565b60408051601f198184030181529082905261108991611a29565b602060405180830381855afa1580156110a6573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906110c99190611b74565b949350505050565b606083516021146110f557604051638152ea1b60e01b815260040160405180910390fd5b825160401461111757604051635e4bd79760e11b815260040160405180910390fd5b604080516020808252818301909252600091602082018180368337019050509050826020820152600085858360405160200161115593929190611ba3565b60408051808303601f190181526014808452838301909252925060009190602082018180368337019050509050815160146020830182602086016069600019fa61119e57600080fd5b509695505050505050565b606060005b825181101561120757818382815181106111ca576111ca611be6565b60200260200101516040516020016111e3929190611bfc565b604051602081830303815290604052915080806111ff90611c34565b9150506111ae565b5060006040518060400160405280601481526020017342696e616e63652d436861696e2d47616e67657360601b8152508787866068548660405160200161125396959493929190611c4d565b60408051601f1981840301815291905280516020909101206067549091506001600160a01b0316611284868361149c565b6001600160a01b0316146112ab576040516356b00a4f60e11b815260040160405180910390fd5b50505050505050565b6000826112c18584611536565b14949350505050565b60606000835160026112dc9190611cbe565b67ffffffffffffffff8111156112f4576112f4611b8d565b6040519080825280601f01601f19166020018201604052801561131e576020820181803683370190505b5060408051808201909152601081526f181899199a1a9b1b9c1cb0b131b232b360811b602082015290915060005b85518110156114645781825187838151811061136a5761136a611be6565b016020015161137c919060f81c611ceb565b8151811061138c5761138c611be6565b01602001516001600160f81b031916836113a7836002611cbe565b815181106113b7576113b7611be6565b60200101906001600160f81b031916908160001a9053508182518783815181106113e3576113e3611be6565b01602001516113f5919060f81c611cff565b8151811061140557611405611be6565b01602001516001600160f81b03191683611420836002611cbe565b61142b906001611d13565b8151811061143b5761143b611be6565b60200101906001600160f81b031916908160001a9053508061145c81611c34565b91505061134c565b508315611494578160405160200161147c9190611d26565b60405160208183030381529060405292505050610ee5565b509392505050565b600082516041146114c0576040516356b00a4f60e11b815260040160405180910390fd5b60208301516040840151606085015160001a601b8110156114e9576114e6601b82611d50565b90505b601b8160ff1610806114fe5750601c8160ff16115b1561151c576040516356b00a4f60e11b815260040160405180910390fd5b600061152a8683868661157b565b50979650505050505050565b600081815b8451811015611494576115678286838151811061155a5761155a611be6565b602002602001015161163f565b91508061157381611c34565b91505061153b565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156115b25750600090506003611636565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611606573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661162f57600060019250925050611636565b9150600090505b94509492505050565b600081831061165b57600082815260208490526040902061166a565b60008381526020839052604090205b9392505050565b80356001600160a01b038116811461168857600080fd5b919050565b60006020828403121561169f57600080fd5b61166a82611671565b600080604083850312156116bb57600080fd5b823591506116cb60208401611671565b90509250929050565b60005b838110156116ef5781810151838201526020016116d7565b50506000910152565b600081518084526117108160208601602086016116d4565b601f01601f19169290920160200192915050565b60208152600061166a60208301846116f8565b60008083601f84011261174957600080fd5b50813567ffffffffffffffff81111561176157600080fd5b60208301915083602082850101111561177957600080fd5b9250929050565b6000806000806040858703121561179657600080fd5b843567ffffffffffffffff808211156117ae57600080fd5b6117ba88838901611737565b909650945060208701359150808211156117d357600080fd5b506117e087828801611737565b95989497509550505050565b60008083601f8401126117fe57600080fd5b50813567ffffffffffffffff81111561181657600080fd5b6020830191508360208260051b850101111561177957600080fd5b60008060008060008060008060008060c08b8d03121561185057600080fd5b8a35995060208b0135985060408b013567ffffffffffffffff8082111561187657600080fd5b6118828e838f01611737565b909a50985060608d013591508082111561189b57600080fd5b6118a78e838f01611737565b909850965060808d01359150808211156118c057600080fd5b6118cc8e838f01611737565b909650945060a08d01359150808211156118e557600080fd5b506118f28d828e016117ec565b915080935050809150509295989b9194979a5092959850565b60006020828403121561191d57600080fd5b5035919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b604081526000611961604083018688611924565b8281036020840152611974818587611924565b979650505050505050565b600084516119918184602089016116d4565b91909101928352506020820152604001919050565b6080815260006119b960808301876116f8565b6020830195909552506001600160a01b03929092166040830152606090910152919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251611a3b8184602087016116d4565b9190910192915050565b7f7b226163636f756e745f6e756d626572223a2230222c22636861696e5f6964228152611d1160f11b602082015260008551611a88816022850160208a016116d4565b7f222c2264617461223a6e756c6c2c226d656d6f223a22222c226d736773223a5b6022918401918201526a3d9130b6b7bab73a111d1160a91b60428201528551611ad981604d840160208a016116d4565b6e1116113932b1b4b834b2b73a111d1160891b604d92909101918201528451611b0981605c8401602089016116d4565b711116113a37b5b2b72fb9bcb6b137b6111d1160711b605c92909101918201528351611b3c81606e8401602088016116d4565b7f227d5d2c2273657175656e6365223a2230222c22736f75726365223a2230227d606e9290910191820152608e019695505050505050565b600060208284031215611b8657600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b60008451611bb58184602089016116d4565b845190830190611bc98183602089016116d4565b8451910190611bdc8183602088016116d4565b0195945050505050565b634e487b7160e01b600052603260045260246000fd5b60008351611c0e8184602088016116d4565b9190910191825250602001919050565b634e487b7160e01b600052601160045260246000fd5b600060018201611c4657611c46611c1e565b5060010190565b60008751611c5f818460208c016116d4565b606088901b6bffffffffffffffffffffffff19169083019081528651611c8c816014840160208b016116d4565b0160148101869052603481018590528351611cae8160548401602088016116d4565b0160540198975050505050505050565b8082028115828204841417610ee557610ee5611c1e565b634e487b7160e01b600052601260045260246000fd5b600082611cfa57611cfa611cd5565b500490565b600082611d0e57611d0e611cd5565b500690565b80820180821115610ee557610ee5611c1e565b61060f60f31b815260008251611d438160028501602087016116d4565b9190910160020192915050565b60ff8181168382160190811115610ee557610ee5611c1e56fea164736f6c6343000811000a" + }, + "04d63aBCd2b9b1baa327f2Dda0f873F197ccd186": { + "balance": "0x19d971e4fe8401e74000000" + }, + "bcdd0d2cda5f6423e57b6a4dcd75decbe31aecf0": { + "balance": "0x19d971e4fe8401e74000000" + }, + "bbd1acc20bd8304309d31d8fd235210d0efc049d": { + "balance": "0x19d971e4fe8401e74000000" + }, + "5e2a531a825d8b61bcc305a35a7433e9a8920f0f": { + "balance": "0x19d971e4fe8401e74000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} \ No newline at end of file