diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 591807e24..1d152114c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -326,7 +326,7 @@ windows: - set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt - set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64 - set RUST_BACKTRACE=1 - - set RUSTFLAGS=%RUSTFLAGS% -Zorbit=off + - set RUSTFLAGS=%RUSTFLAGS% - rustup default stable-x86_64-pc-windows-msvc - cargo build --release %CARGOFLAGS% - curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll diff --git a/.travis.yml b/.travis.yml index 80bf9ba10..6f3fd9933 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: include: - rust: stable env: RUN_TESTS="true" TEST_OPTIONS="--no-release" - - rust: beta + - rust: stable env: RUN_COVERAGE="true" - rust: stable env: RUN_DOCS="true" diff --git a/Cargo.lock b/Cargo.lock index b53b28426..572d92616 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1250,7 +1250,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#bc1728a4d24c098ee8792372c14dff98f954518c" +source = "git+https://github.com/ethcore/js-precompiled.git#b2513e92603b473799d653583bd86771e0063c08" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1927,7 +1927,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ws" version = "0.5.3" -source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#0cd6c5e3e9d5e61a37d53eb8dcbad523dcc69314" +source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#f5c0b35d660244d1b7500693c8cc28277ce1d418" dependencies = [ "bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)", "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/res/authority_round.json b/ethcore/res/authority_round.json new file mode 100644 index 000000000..ad23b461f --- /dev/null +++ b/ethcore/res/authority_round.json @@ -0,0 +1,42 @@ +{ + "name": "TestAuthorityRound", + "engine": { + "AuthorityRound": { + "params": { + "gasLimitBoundDivisor": "0x0400", + "stepDuration": "1", + "authorities" : [ + "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e", + "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1" + ] + } + } + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x69" + }, + "genesis": { + "seal": { + "generic": { + "fields": 1, + "rlp": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa" + } + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2fefd8" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } + } +} diff --git a/ethcore/res/test_authority.json b/ethcore/res/basic_authority.json similarity index 98% rename from ethcore/res/test_authority.json rename to ethcore/res/basic_authority.json index 1ab482863..51276d487 100644 --- a/ethcore/res/test_authority.json +++ b/ethcore/res/basic_authority.json @@ -1,5 +1,5 @@ { - "name": "TestAuthority", + "name": "TestBasicAuthority", "engine": { "BasicAuthority": { "params": { diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index be473237c..9bb9c50ff 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -131,10 +131,11 @@ "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], "eip150Transition": "0x259518", - "eip155Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "eip155Transition": 2675000, + "eip160Transition": 2675000, + "eip161abcTransition": 2675000, + "eip161dTransition": 2675000, + "maxCodeSize": 24576 } } }, diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 9d54169c3..6e725e8bf 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -11,10 +11,10 @@ "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d", "homesteadTransition": "0x789b0", "eip150Transition": "0x1b34d8", - "eip155Transition": "0x7fffffffffffffff", - "eip160Transition": "0x7fffffffffffffff", - "eip161abcTransition": "0x7fffffffffffffff", - "eip161dTransition": "0x7fffffffffffffff" + "eip155Transition": 1885000, + "eip160Transition": 1885000, + "eip161abcTransition": 1885000, + "eip161dTransition": 1885000 } } }, diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index b7c29a01f..2d5b38659 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -1,5 +1,5 @@ { - "name": "TestInstantSeal", + "name": "DevelopmentChain", "engine": { "InstantSeal": null }, @@ -28,6 +28,6 @@ "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } + "0x00a329c0648769a73afac7f9381e08fb43dbea72": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 83f1f3709..14558f6c6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -556,6 +556,7 @@ impl Client { /// Import transactions from the IO queue pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize { + trace!(target: "external_tx", "Importing queued"); let _timer = PerfTimer::new("import_queued_transactions"); self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst); let txs = transactions.iter().filter_map(|bytes| UntrustedRlp::new(bytes).as_val().ok()).collect(); @@ -563,6 +564,11 @@ impl Client { results.len() } + /// Used by PoA to try sealing on period change. + pub fn update_sealing(&self) { + self.miner.update_sealing(self) + } + /// Attempt to get a copy of a specific block's final state. /// /// This will not fail if given BlockID::Latest. @@ -1254,7 +1260,9 @@ impl BlockChainClient for Client { } fn queue_transactions(&self, transactions: Vec) { - if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE { + let queue_size = self.queue_transactions.load(AtomicOrdering::Relaxed); + trace!(target: "external_tx", "Queue size: {}", queue_size); + if queue_size > MAX_TX_QUEUE_SIZE { debug!("Ignoring {} transactions: queue is full", transactions.len()); } else { let len = transactions.len(); diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 434edd3e8..84ed25b37 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -119,6 +119,16 @@ impl TestBlockChainClient { /// Creates new test client with specified extra data for each block pub fn new_with_extra_data(extra_data: Bytes) -> Self { let spec = Spec::new_test(); + TestBlockChainClient::new_with_spec_and_extra(spec, extra_data) + } + + /// Create test client with custom spec. + pub fn new_with_spec(spec: Spec) -> Self { + TestBlockChainClient::new_with_spec_and_extra(spec, Bytes::new()) + } + + /// Create test client with custom spec and extra data. + pub fn new_with_spec_and_extra(spec: Spec, extra_data: Bytes) -> Self { let mut client = TestBlockChainClient { blocks: RwLock::new(HashMap::new()), numbers: RwLock::new(HashMap::new()), @@ -315,7 +325,7 @@ pub fn get_temp_state_db() -> GuardedTempResult { impl MiningBlockChainClient for TestBlockChainClient { fn latest_schedule(&self) -> Schedule { - Schedule::new_post_eip150(true, true, true) + Schedule::new_post_eip150(24576, true, true, true) } fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs new file mode 100644 index 000000000..9bed99e8b --- /dev/null +++ b/ethcore/src/engines/authority_round.rs @@ -0,0 +1,429 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! A blockchain engine that supports a non-instant BFT proof-of-authority. + +use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; +use std::sync::Weak; +use std::time::{UNIX_EPOCH, Duration}; +use util::*; +use ethkey::{verify_address, Signature}; +use rlp::{UntrustedRlp, View, encode}; +use account_provider::AccountProvider; +use block::*; +use spec::CommonParams; +use engines::Engine; +use header::Header; +use error::{Error, BlockError}; +use evm::Schedule; +use ethjson; +use io::{IoContext, IoHandler, TimerToken, IoService, IoChannel}; +use service::ClientIoMessage; +use transaction::SignedTransaction; +use env_info::EnvInfo; +use builtin::Builtin; + +/// `AuthorityRound` params. +#[derive(Debug, PartialEq)] +pub struct AuthorityRoundParams { + /// Gas limit divisor. + pub gas_limit_bound_divisor: U256, + /// Time to wait before next block or authority switching. + pub step_duration: Duration, + /// Valid authorities. + pub authorities: Vec
, + /// Number of authorities. + pub authority_n: usize, +} + +impl From for AuthorityRoundParams { + fn from(p: ethjson::spec::AuthorityRoundParams) -> Self { + AuthorityRoundParams { + gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), + step_duration: Duration::from_secs(p.step_duration.into()), + authority_n: p.authorities.len(), + authorities: p.authorities.into_iter().map(Into::into).collect::>(), + } + } +} + +/// Engine using `AuthorityRound` proof-of-work consensus algorithm, suitable for Ethereum +/// mainnet chains in the Olympic, Frontier and Homestead eras. +pub struct AuthorityRound { + params: CommonParams, + our_params: AuthorityRoundParams, + builtins: BTreeMap, + transition_service: IoService, + message_channel: Mutex>>, + step: AtomicUsize, + proposed: AtomicBool, +} + +fn header_step(header: &Header) -> Result { + UntrustedRlp::new(&header.seal()[0]).as_val() +} + +fn header_signature(header: &Header) -> Result { + UntrustedRlp::new(&header.seal()[1]).as_val::().map(Into::into) +} + +trait AsMillis { + fn as_millis(&self) -> u64; +} + +impl AsMillis for Duration { + fn as_millis(&self) -> u64 { + self.as_secs()*1_000 + (self.subsec_nanos()/1_000_000) as u64 + } +} + +impl AuthorityRound { + /// Create a new instance of AuthorityRound engine. + pub fn new(params: CommonParams, our_params: AuthorityRoundParams, builtins: BTreeMap) -> Result, Error> { + let initial_step = (unix_now().as_secs() / our_params.step_duration.as_secs()) as usize; + let engine = Arc::new( + AuthorityRound { + params: params, + our_params: our_params, + builtins: builtins, + transition_service: try!(IoService::::start()), + message_channel: Mutex::new(None), + step: AtomicUsize::new(initial_step), + proposed: AtomicBool::new(false) + }); + let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; + try!(engine.transition_service.register_handler(Arc::new(handler))); + Ok(engine) + } + + fn step(&self) -> usize { + self.step.load(AtomicOrdering::SeqCst) + } + + fn remaining_step_duration(&self) -> Duration { + let now = unix_now(); + let step_end = self.our_params.step_duration * (self.step() as u32 + 1); + if step_end > now { + step_end - now + } else { + Duration::from_secs(0) + } + } + + fn step_proposer(&self, step: usize) -> &Address { + let ref p = self.our_params; + p.authorities.get(step % p.authority_n).expect("There are authority_n authorities; taking number modulo authority_n gives number in authority_n range; qed") + } + + fn is_step_proposer(&self, step: usize, address: &Address) -> bool { + self.step_proposer(step) == address + } +} + +fn unix_now() -> Duration { + UNIX_EPOCH.elapsed().expect("Valid time has to be set in your system.") +} + +struct TransitionHandler { + engine: Weak, +} + +#[derive(Clone)] +struct BlockArrived; + +const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; + +impl IoHandler for TransitionHandler { + fn initialize(&self, io: &IoContext) { + if let Some(engine) = self.engine.upgrade() { + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, engine.remaining_step_duration().as_millis()) + .unwrap_or_else(|e| warn!(target: "poa", "Failed to start consensus step timer: {}.", e)) + } + } + + fn timeout(&self, io: &IoContext, timer: TimerToken) { + if timer == ENGINE_TIMEOUT_TOKEN { + if let Some(engine) = self.engine.upgrade() { + engine.step.fetch_add(1, AtomicOrdering::SeqCst); + engine.proposed.store(false, AtomicOrdering::SeqCst); + if let Some(ref channel) = *engine.message_channel.lock() { + match channel.send(ClientIoMessage::UpdateSealing) { + Ok(_) => trace!(target: "poa", "timeout: UpdateSealing message sent for step {}.", engine.step.load(AtomicOrdering::Relaxed)), + Err(err) => trace!(target: "poa", "timeout: Could not send a sealing message {} for step {}.", err, engine.step.load(AtomicOrdering::Relaxed)), + } + } + io.register_timer_once(ENGINE_TIMEOUT_TOKEN, engine.remaining_step_duration().as_millis()) + .unwrap_or_else(|e| warn!(target: "poa", "Failed to restart consensus step timer: {}.", e)) + } + } + } +} + +impl Engine for AuthorityRound { + fn name(&self) -> &str { "AuthorityRound" } + fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) } + /// Two fields - consensus step and the corresponding proposer signature. + fn seal_fields(&self) -> usize { 2 } + + fn params(&self) -> &CommonParams { &self.params } + fn builtins(&self) -> &BTreeMap { &self.builtins } + + /// Additional engine-specific information for the user/developer concerning `header`. + fn extra_info(&self, header: &Header) -> BTreeMap { + map![ + "step".into() => header_step(header).as_ref().map(ToString::to_string).unwrap_or("".into()), + "signature".into() => header_signature(header).as_ref().map(ToString::to_string).unwrap_or("".into()) + ] + } + + fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + Schedule::new_post_eip150(usize::max_value(), true, true, true) + } + + fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { + header.set_difficulty(parent.difficulty().clone()); + header.set_gas_limit({ + let gas_limit = parent.gas_limit().clone(); + let bound_divisor = self.our_params.gas_limit_bound_divisor; + if gas_limit < gas_floor_target { + min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) + } else { + max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) + } + }); + } + + /// Apply the block reward on finalisation of the block. + /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). + fn on_close_block(&self, _block: &mut ExecutedBlock) {} + + fn is_sealer(&self, author: &Address) -> Option { + let ref p = self.our_params; + Some(p.authorities.contains(author)) + } + + /// Attempt to seal the block internally. + /// + /// This operation is synchronous and may (quite reasonably) not be available, in which `false` will + /// be returned. + fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option> { + if self.proposed.load(AtomicOrdering::SeqCst) { return None; } + let header = block.header(); + let step = self.step(); + if self.is_step_proposer(step, header.author()) { + if let Some(ap) = accounts { + // Account should be permanently unlocked, otherwise sealing will fail. + if let Ok(signature) = ap.sign(*header.author(), None, header.bare_hash()) { + trace!(target: "poa", "generate_seal: Issuing a block for step {}.", step); + self.proposed.store(true, AtomicOrdering::SeqCst); + return Some(vec![encode(&step).to_vec(), encode(&(&*signature as &[u8])).to_vec()]); + } else { + warn!(target: "poa", "generate_seal: FAIL: Accounts secret key unavailable."); + } + } else { + warn!(target: "poa", "generate_seal: FAIL: Accounts not provided."); + } + } + None + } + + /// Check the number of seal fields. + fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { + if header.seal().len() != self.seal_fields() { + trace!(target: "poa", "verify_block_basic: wrong number of seal fields"); + Err(From::from(BlockError::InvalidSealArity( + Mismatch { expected: self.seal_fields(), found: header.seal().len() } + ))) + } else { + Ok(()) + } + } + + /// Check if the signature belongs to the correct proposer. + fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { + let header_step = try!(header_step(header)); + // Give one step slack if step is lagging, double vote is still not possible. + if header_step <= self.step() + 1 { + let proposer_signature = try!(header_signature(header)); + let ok_sig = try!(verify_address(self.step_proposer(header_step), &proposer_signature, &header.bare_hash())); + if ok_sig { + Ok(()) + } else { + trace!(target: "poa", "verify_block_unordered: invalid seal signature"); + try!(Err(BlockError::InvalidSeal)) + } + } else { + trace!(target: "poa", "verify_block_unordered: block from the future"); + try!(Err(BlockError::InvalidSeal)) + } + } + + fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { + // Don't calculate difficulty for genesis blocks. + if header.number() == 0 { + return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))); + } + + let step = try!(header_step(header)); + // Check if parent is from a previous step. + if step == try!(header_step(parent)) { + trace!(target: "poa", "Multiple blocks proposed for step {}.", step); + try!(Err(BlockError::DoubleVote(header.author().clone()))); + } + + // Check difficulty is correct given the two timestamps. + if header.difficulty() != parent.difficulty() { + return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: *parent.difficulty(), found: *header.difficulty() }))) + } + let gas_limit_divisor = self.our_params.gas_limit_bound_divisor; + let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; + let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; + if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas { + return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }))); + } + Ok(()) + } + + fn verify_transaction_basic(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { + try!(t.check_low_s()); + Ok(()) + } + + fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { + t.sender().map(|_|()) // Perform EC recovery and cache sender + } + + fn register_message_channel(&self, message_channel: IoChannel) { + let mut guard = self.message_channel.lock(); + *guard = Some(message_channel); + } +} + +#[cfg(test)] +mod tests { + use util::*; + use env_info::EnvInfo; + use header::Header; + use error::{Error, BlockError}; + use rlp::encode; + use block::*; + use tests::helpers::*; + use account_provider::AccountProvider; + use spec::Spec; + use std::time::UNIX_EPOCH; + + #[test] + fn has_valid_metadata() { + let engine = Spec::new_test_round().engine; + assert!(!engine.name().is_empty()); + assert!(engine.version().major >= 1); + } + + #[test] + fn can_return_schedule() { + let engine = Spec::new_test_round().engine; + let schedule = engine.schedule(&EnvInfo { + number: 10000000, + author: 0.into(), + timestamp: 0, + difficulty: 0.into(), + last_hashes: Arc::new(vec![]), + gas_used: 0.into(), + gas_limit: 0.into(), + }); + + assert!(schedule.stack_limit > 0); + } + + #[test] + fn verification_fails_on_short_seal() { + let engine = Spec::new_test_round().engine; + let header: Header = Header::default(); + + let verify_result = engine.verify_block_basic(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_do_signature_verification_fail() { + let engine = Spec::new_test_round().engine; + let mut header: Header = Header::default(); + header.set_seal(vec![encode(&H520::default()).to_vec()]); + + let verify_result = engine.verify_block_unordered(&header, None); + assert!(verify_result.is_err()); + } + + #[test] + fn generates_seal_and_does_not_double_propose() { + let tap = AccountProvider::transient_provider(); + let addr1 = tap.insert_account("1".sha3(), "1").unwrap(); + tap.unlock_account_permanently(addr1, "1".into()).unwrap(); + let addr2 = tap.insert_account("2".sha3(), "2").unwrap(); + tap.unlock_account_permanently(addr2, "2".into()).unwrap(); + + let spec = Spec::new_test_round(); + let engine = &*spec.engine; + let genesis_header = spec.genesis_header(); + let mut db1 = get_temp_state_db().take(); + spec.ensure_db_good(&mut db1).unwrap(); + let mut db2 = get_temp_state_db().take(); + spec.ensure_db_good(&mut db2).unwrap(); + let last_hashes = Arc::new(vec![genesis_header.hash()]); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b1 = b1.close_and_lock(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b2 = b2.close_and_lock(); + + if let Some(seal) = engine.generate_seal(b1.block(), Some(&tap)) { + assert!(b1.clone().try_seal(engine, seal).is_ok()); + // Second proposal is forbidden. + assert!(engine.generate_seal(b1.block(), Some(&tap)).is_none()); + } + + if let Some(seal) = engine.generate_seal(b2.block(), Some(&tap)) { + assert!(b2.clone().try_seal(engine, seal).is_ok()); + // Second proposal is forbidden. + assert!(engine.generate_seal(b2.block(), Some(&tap)).is_none()); + } + } + + #[test] + fn proposer_switching() { + let mut header: Header = Header::default(); + let tap = AccountProvider::transient_provider(); + let addr = tap.insert_account("0".sha3(), "0").unwrap(); + + header.set_author(addr); + + let engine = Spec::new_test_round().engine; + + let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); + let mut step = UNIX_EPOCH.elapsed().unwrap().as_secs(); + header.set_seal(vec![encode(&step).to_vec(), encode(&(&*signature as &[u8])).to_vec()]); + let first_ok = engine.verify_block_seal(&header).is_ok(); + step = step + 1; + header.set_seal(vec![encode(&step).to_vec(), encode(&(&*signature as &[u8])).to_vec()]); + let second_ok = engine.verify_block_seal(&header).is_ok(); + + assert!(first_ok ^ second_ok); + } +} diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 5a55c6210..23a97967c 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -181,13 +181,6 @@ impl Engine for BasicAuthority { } } -impl Header { - /// Get the none field of the header. - pub fn signature(&self) -> H520 { - ::rlp::decode(&self.seal()[0]) - } -} - #[cfg(test)] mod tests { use util::*; @@ -201,7 +194,7 @@ mod tests { /// Create a new test chain spec with `BasicAuthority` consensus engine. fn new_test_authority() -> Spec { - let bytes: &[u8] = include_bytes!("../../res/test_authority.json"); + let bytes: &[u8] = include_bytes!("../../res/basic_authority.json"); Spec::load(bytes).expect("invalid chain spec") } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index acead19b4..3dc78d1a2 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -55,7 +55,7 @@ impl Engine for InstantSeal { } fn schedule(&self, _env_info: &EnvInfo) -> Schedule { - Schedule::new_homestead() + Schedule::new_post_eip150(usize::max_value(), false, false, false) } fn is_sealer(&self, _author: &Address) -> Option { Some(true) } @@ -79,7 +79,7 @@ mod tests { let tap = AccountProvider::transient_provider(); let addr = tap.insert_account("".sha3(), "").unwrap(); - let spec = Spec::new_test_instant(); + let spec = Spec::new_instant(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); @@ -95,7 +95,7 @@ mod tests { #[test] fn instant_cant_verify() { - let engine = Spec::new_test_instant().engine; + let engine = Spec::new_instant().engine; let mut header: Header = Header::default(); assert!(engine.verify_block_basic(&header, None).is_ok()); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 52812f45e..c70a19de8 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -19,10 +19,12 @@ mod null_engine; mod instant_seal; mod basic_authority; +mod authority_round; pub use self::null_engine::NullEngine; pub use self::instant_seal::InstantSeal; pub use self::basic_authority::BasicAuthority; +pub use self::authority_round::AuthorityRound; use util::*; use account_provider::AccountProvider; @@ -32,6 +34,8 @@ use env_info::EnvInfo; use error::Error; use spec::CommonParams; use evm::Schedule; +use io::IoChannel; +use service::ClientIoMessage; use header::Header; use transaction::SignedTransaction; @@ -140,5 +144,7 @@ pub trait Engine : Sync + Send { self.builtins().get(a).expect("attempted to execute nonexistent builtin").execute(input, output); } + /// Add a channel for communication with Client which can be used for sealing. + fn register_message_channel(&self, _message_channel: IoChannel) {} // TODO: sealing stuff - though might want to leave this for later. } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index ae68aefa1..261eab268 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -167,6 +167,8 @@ pub enum BlockError { UnknownParent(H256), /// Uncle parent given is unknown. UnknownUncleParent(H256), + /// The same author issued different votes at the same step. + DoubleVote(H160), } impl fmt::Display for BlockError { @@ -200,6 +202,7 @@ impl fmt::Display for BlockError { RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), UnknownParent(ref hash) => format!("Unknown parent: {}", hash), UnknownUncleParent(ref hash) => format!("Unknown uncle parent: {}", hash), + DoubleVote(ref address) => format!("Author {} issued too many blocks.", address), }; f.write_fmt(format_args!("Block error ({})", msg)) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 6436e3531..de2a85942 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -73,7 +73,9 @@ pub struct EthashParams { /// Number of first block where ECIP-1010 begins. pub ecip1010_pause_transition: u64, /// Number of first block where ECIP-1010 ends. - pub ecip1010_continue_transition: u64 + pub ecip1010_continue_transition: u64, + /// Maximum amount of code that can be deploying into a contract. + pub max_code_size: u64, } impl From for EthashParams { @@ -87,19 +89,20 @@ impl From for EthashParams { block_reward: p.block_reward.into(), registrar: p.registrar.map_or_else(Address::new, Into::into), homestead_transition: p.homestead_transition.map_or(0, Into::into), - dao_hardfork_transition: p.dao_hardfork_transition.map_or(0x7fffffffffffffff, Into::into), + dao_hardfork_transition: p.dao_hardfork_transition.map_or(u64::max_value(), Into::into), dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into), dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(), - difficulty_hardfork_transition: p.difficulty_hardfork_transition.map_or(0x7fffffffffffffff, Into::into), + difficulty_hardfork_transition: p.difficulty_hardfork_transition.map_or(u64::max_value(), Into::into), difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into), - bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into), + bomb_defuse_transition: p.bomb_defuse_transition.map_or(u64::max_value(), Into::into), eip150_transition: p.eip150_transition.map_or(0, Into::into), eip155_transition: p.eip155_transition.map_or(0, Into::into), eip160_transition: p.eip160_transition.map_or(0, Into::into), eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), - eip161d_transition: p.eip161d_transition.map_or(0x7fffffffffffffff, Into::into), - ecip1010_pause_transition: p.ecip1010_pause_transition.map_or(0x7fffffffffffffff, Into::into), - ecip1010_continue_transition: p.ecip1010_continue_transition.map_or(0x7fffffffffffffff, Into::into), + eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into), + ecip1010_pause_transition: p.ecip1010_pause_transition.map_or(u64::max_value(), Into::into), + ecip1010_continue_transition: p.ecip1010_continue_transition.map_or(u64::max_value(), Into::into), + max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into), } } } @@ -152,6 +155,7 @@ impl Engine for Ethash { Schedule::new_homestead() } else { Schedule::new_post_eip150( + self.ethash_params.max_code_size as usize, env_info.number >= self.ethash_params.eip160_transition, env_info.number >= self.ethash_params.eip161abc_transition, env_info.number >= self.ethash_params.eip161d_transition diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index b68f6acb5..773708956 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -70,6 +70,8 @@ pub struct Schedule { pub quad_coeff_div: usize, /// Cost for contract length when executing `CREATE` pub create_data_gas: usize, + /// Maximum code size when creating a contract. + pub create_data_limit: usize, /// Transaction cost pub tx_gas: usize, /// `CREATE` transaction cost @@ -111,7 +113,7 @@ impl Schedule { } /// Schedule for the post-EIP-150-era of the Ethereum main net. - pub fn new_post_eip150(fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule { + pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule { Schedule { exceptional_failed_code_deposit: true, have_delegate_call: true, @@ -139,6 +141,7 @@ impl Schedule { memory_gas: 3, quad_coeff_div: 512, create_data_gas: 200, + create_data_limit: max_code_size, tx_gas: 21000, tx_create_gas: 53000, tx_data_zero_gas: 4, @@ -183,6 +186,7 @@ impl Schedule { memory_gas: 3, quad_coeff_div: 512, create_data_gas: 200, + create_data_limit: usize::max_value(), tx_gas: 21000, tx_create_gas: tcg, tx_data_zero_gas: 4, diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index df1b64e67..3704ead67 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -242,7 +242,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT }, OutputPolicy::InitContract(ref mut copy) => { let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); - if return_cost > *gas { + if return_cost > *gas || data.len() > self.schedule.create_data_limit { return match self.schedule.exceptional_failed_code_deposit { true => Err(evm::Error::OutOfGas), false => Ok(*gas) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 19a2b9a10..84e29458d 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -212,7 +212,8 @@ pub struct Miner { sealing_block_last_request: Mutex, // for sealing... options: MinerOptions, - seals_internally: bool, + /// Does the node perform internal (without work) sealing. + pub seals_internally: bool, gas_range_target: RwLock<(U256, U256)>, author: RwLock
, @@ -267,6 +268,11 @@ impl Miner { } } + /// Creates new instance of miner with accounts and with given spec. + pub fn with_spec_and_accounts(spec: &Spec, accounts: Option>) -> Miner { + Miner::new_raw(Default::default(), GasPricer::new_fixed(20_000_000_000u64.into()), spec, accounts) + } + /// Creates new instance of miner without accounts, but with given spec. pub fn with_spec(spec: &Spec) -> Miner { Miner::new_raw(Default::default(), GasPricer::new_fixed(20_000_000_000u64.into()), spec, None) @@ -429,6 +435,7 @@ impl Miner { let last_request = *self.sealing_block_last_request.lock(); let should_disable_sealing = !self.forced_sealing() && !has_local_transactions + && !self.seals_internally && best_block > last_request && best_block - last_request > SEALING_TIMEOUT_IN_BLOCKS; @@ -472,9 +479,10 @@ impl Miner { /// Uses Engine to seal the block internally and then imports it to chain. fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool { - if !block.transactions().is_empty() { + if !block.transactions().is_empty() || self.forced_sealing() { if let Ok(sealed) = self.seal_block_internally(block) { if chain.import_block(sealed.rlp_bytes()).is_ok() { + trace!(target: "miner", "import_block_internally: imported internally sealed block"); return true } } @@ -773,7 +781,7 @@ impl MinerService for Miner { chain: &MiningBlockChainClient, transactions: Vec ) -> Vec> { - + trace!(target: "external_tx", "Importing external transactions"); let results = { let mut transaction_queue = self.transaction_queue.lock(); self.add_transactions_to_queue( @@ -1251,7 +1259,7 @@ mod tests { #[test] fn internal_seals_without_work() { - let miner = Miner::with_spec(&Spec::new_test_instant()); + let miner = Miner::with_spec(&Spec::new_instant()); let c = generate_dummy_client(2); let client = c.reference().as_ref(); diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 00ba981b9..36b5e7157 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -48,6 +48,8 @@ pub enum ClientIoMessage { FeedBlockChunk(H256, Bytes), /// Take a snapshot for the block with given number. TakeSnapshot(u64), + /// Trigger sealing update (useful for internal sealing). + UpdateSealing, } /// Client service setup. Creates and registers client and network services with the IO subsystem. @@ -111,6 +113,8 @@ impl ClientService { }); try!(io_service.register_handler(client_io)); + spec.engine.register_message_channel(io_service.channel()); + let stop_guard = ::devtools::StopGuard::new(); run_ipc(ipc_path, client.clone(), snapshot.clone(), stop_guard.share()); @@ -213,8 +217,11 @@ impl IoHandler for ClientIoHandler { if let Err(e) = res { debug!(target: "snapshot", "Failed to initialize periodic snapshot thread: {:?}", e); } - - } + }, + ClientIoMessage::UpdateSealing => { + trace!(target: "authorityround", "message: UpdateSealing"); + self.client.update_sealing() + }, _ => {} // ignore other messages } } diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 38a4028e1..327979ce3 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -19,11 +19,11 @@ use account_db::{AccountDB, AccountDBMut}; use snapshot::Error; -use util::{U256, FixedHash, H256, Bytes, HashDB, DBValue, SHA3_EMPTY, SHA3_NULL_RLP}; +use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP}; use util::trie::{TrieDB, Trie}; use rlp::{Rlp, RlpStream, Stream, UntrustedRlp, View}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; // An empty account -- these are replaced with RLP null data for a space optimization. const ACC_EMPTY: Account = Account { @@ -150,7 +150,6 @@ impl Account { pub fn from_fat_rlp( acct_db: &mut AccountDBMut, rlp: UntrustedRlp, - code_map: &HashMap, ) -> Result<(Self, Option), Error> { use util::{TrieDBMut, TrieMut}; @@ -177,9 +176,6 @@ impl Account { } CodeState::Hash => { let code_hash = try!(rlp.val_at(3)); - if let Some(code) = code_map.get(&code_hash) { - acct_db.emplace(code_hash.clone(), DBValue::from_slice(code)); - } (code_hash, None) } @@ -229,7 +225,7 @@ mod tests { use util::{Address, FixedHash, H256, HashDB, DBValue}; use rlp::{UntrustedRlp, View}; - use std::collections::{HashSet, HashMap}; + use std::collections::HashSet; use super::{ACC_EMPTY, Account}; @@ -250,7 +246,7 @@ mod tests { let fat_rlp = account.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &addr), &mut Default::default()).unwrap(); let fat_rlp = UntrustedRlp::new(&fat_rlp); - assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, &Default::default()).unwrap().0, account); + assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap().0, account); } #[test] @@ -275,7 +271,7 @@ mod tests { let fat_rlp = account.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &addr), &mut Default::default()).unwrap(); let fat_rlp = UntrustedRlp::new(&fat_rlp); - assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, &Default::default()).unwrap().0, account); + assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap().0, account); } #[test] @@ -318,12 +314,11 @@ mod tests { let fat_rlp1 = UntrustedRlp::new(&fat_rlp1); let fat_rlp2 = UntrustedRlp::new(&fat_rlp2); - let code_map = HashMap::new(); - let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, &code_map).unwrap(); + let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2).unwrap(); assert!(maybe_code.is_none()); assert_eq!(acc, account2); - let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr1), fat_rlp1, &code_map).unwrap(); + let (acc, maybe_code) = Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr1), fat_rlp1).unwrap(); assert_eq!(maybe_code, Some(b"this is definitely code".to_vec())); assert_eq!(acc, account1); } @@ -332,9 +327,8 @@ mod tests { fn encoding_empty_acc() { let mut db = get_temp_state_db(); let mut used_code = HashSet::new(); - let code_map = HashMap::new(); assert_eq!(ACC_EMPTY.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &Address::default()), &mut used_code).unwrap(), ::rlp::NULL_RLP.to_vec()); - assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), &code_map).unwrap(), (ACC_EMPTY, None)); + assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP)).unwrap(), (ACC_EMPTY, None)); } } diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index f4d791593..3f63ac208 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -389,7 +389,7 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex, state_root: H256, - code_map: HashMap, // maps code hashes to code itself. + known_code: HashMap, // code hashes mapped to first account with this code. missing_code: HashMap>, // maps code hashes to lists of accounts missing that code. bloom: Bloom, } @@ -400,7 +400,7 @@ impl StateRebuilder { StateRebuilder { db: journaldb::new(db.clone(), pruning, ::db::COL_STATE), state_root: SHA3_NULL_RLP, - code_map: HashMap::new(), + known_code: HashMap::new(), missing_code: HashMap::new(), bloom: StateDB::load_bloom(&*db), } @@ -419,7 +419,7 @@ impl StateRebuilder { self.db.as_hashdb_mut(), rlp, &mut pairs, - &self.code_map, + &self.known_code, flag )); @@ -428,13 +428,13 @@ impl StateRebuilder { } // patch up all missing code. must be done after collecting all new missing code entries. - for (code_hash, code) in status.new_code { + for (code_hash, code, first_with) in status.new_code { for addr_hash in self.missing_code.remove(&code_hash).unwrap_or_else(Vec::new) { let mut db = AccountDBMut::from_hash(self.db.as_hashdb_mut(), addr_hash); db.emplace(code_hash, DBValue::from_slice(&code)); } - self.code_map.insert(code_hash, code); + self.known_code.insert(code_hash, first_with); } let backing = self.db.backing().clone(); @@ -482,7 +482,8 @@ impl StateRebuilder { #[derive(Default)] struct RebuiltStatus { - new_code: Vec<(H256, Bytes)>, // new code that's become available. + // new code that's become available. (code_hash, code, addr_hash) + new_code: Vec<(H256, Bytes, H256)>, missing_code: Vec<(H256, H256)>, // accounts that are missing code. } @@ -492,10 +493,9 @@ fn rebuild_accounts( db: &mut HashDB, account_fat_rlps: UntrustedRlp, out_chunk: &mut [(H256, Bytes)], - code_map: &HashMap, - abort_flag: &AtomicBool -) -> Result -{ + known_code: &HashMap, + abort_flag: &AtomicBool, +) -> Result { let mut status = RebuiltStatus::default(); for (account_rlp, out) in account_fat_rlps.into_iter().zip(out_chunk) { if !abort_flag.load(Ordering::SeqCst) { return Err(Error::RestorationAborted.into()) } @@ -504,17 +504,33 @@ fn rebuild_accounts( let fat_rlp = try!(account_rlp.at(1)); let thin_rlp = { - let mut acct_db = AccountDBMut::from_hash(db, hash); // fill out the storage trie and code while decoding. - let (acc, maybe_code) = try!(Account::from_fat_rlp(&mut acct_db, fat_rlp, code_map)); + let (acc, maybe_code) = { + let mut acct_db = AccountDBMut::from_hash(db, hash); + try!(Account::from_fat_rlp(&mut acct_db, fat_rlp)) + }; let code_hash = acc.code_hash().clone(); match maybe_code { - Some(code) => status.new_code.push((code_hash, code)), + // new inline code + Some(code) => status.new_code.push((code_hash, code, hash)), None => { - if code_hash != ::util::SHA3_EMPTY && !code_map.contains_key(&code_hash) { - status.missing_code.push((hash, code_hash)); + if code_hash != ::util::SHA3_EMPTY { + // see if this code has already been included inline + match known_code.get(&code_hash) { + Some(&first_with) => { + // if so, load it from the database. + let code = try!(AccountDB::from_hash(db, first_with) + .get(&code_hash) + .ok_or_else(|| Error::MissingCode(vec![first_with]))); + + // and write it again under a different mangled key + AccountDBMut::from_hash(db, hash).emplace(code_hash, code); + } + // if not, queue it up to be filled later + None => status.missing_code.push((hash, code_hash)), + } } } } diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index 05537fa96..36c268f73 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -17,6 +17,7 @@ //! State snapshotting tests. use snapshot::{chunk_state, Error as SnapshotError, Progress, StateRebuilder}; +use snapshot::account::Account; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; use super::helpers::{compare_dbs, StateProducer}; @@ -30,6 +31,8 @@ use util::memorydb::MemoryDB; use util::Mutex; use devtools::RandomTempPath; +use util::sha3::SHA3_NULL_RLP; + use std::sync::Arc; use std::sync::atomic::AtomicBool; @@ -88,6 +91,58 @@ fn snap_and_restore() { compare_dbs(&old_db, new_db.as_hashdb()); } +#[test] +fn get_code_from_prev_chunk() { + use std::collections::HashSet; + use rlp::{RlpStream, Stream}; + use util::{HashDB, H256, FixedHash, U256, Hashable}; + + use account_db::{AccountDBMut, AccountDB}; + + let code = b"this is definitely code"; + let mut used_code = HashSet::new(); + let mut acc_stream = RlpStream::new_list(4); + acc_stream.append(&U256::default()) + .append(&U256::default()) + .append(&SHA3_NULL_RLP) + .append(&code.sha3()); + + let (h1, h2) = (H256::random(), H256::random()); + + // two accounts with the same code, one per chunk. + // first one will have code inlined, + // second will just have its hash. + let thin_rlp = acc_stream.out(); + let acc1 = Account::from_thin_rlp(&thin_rlp); + let acc2 = Account::from_thin_rlp(&thin_rlp); + + let mut make_chunk = |acc: Account, hash| { + let mut db = MemoryDB::new(); + AccountDBMut::from_hash(&mut db, hash).insert(&code[..]); + + let fat_rlp = acc.to_fat_rlp(&AccountDB::from_hash(&db, hash), &mut used_code).unwrap(); + + let mut stream = RlpStream::new_list(1); + stream.begin_list(2).append(&hash).append_raw(&fat_rlp, 1); + stream.out() + }; + + let chunk1 = make_chunk(acc1, h1); + let chunk2 = make_chunk(acc2, h2); + + let db_path = RandomTempPath::create_dir(); + let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS); + let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap()); + + let mut rebuilder = StateRebuilder::new(new_db, Algorithm::Archive); + let flag = AtomicBool::new(true); + + rebuilder.feed(&chunk1, &flag).unwrap(); + rebuilder.feed(&chunk2, &flag).unwrap(); + + rebuilder.check_missing().unwrap(); +} + #[test] fn checks_flag() { let mut producer = StateProducer::new(); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 6bfb1bcc1..c8910bbdd 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -18,7 +18,7 @@ use util::*; use builtin::Builtin; -use engines::{Engine, NullEngine, InstantSeal, BasicAuthority}; +use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound}; use pod_state::*; use account_db::*; use header::{BlockNumber, Header}; @@ -135,6 +135,12 @@ impl From for Spec { } } +macro_rules! load_bundled { + ($e:expr) => { + Spec::load(include_bytes!(concat!("../../res/", $e, ".json")) as &[u8]).expect(concat!("Chain spec ", $e, " is invalid.")) + }; +} + impl Spec { /// Convert engine spec into a arc'd Engine of the right underlying type. /// TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. @@ -144,6 +150,7 @@ impl Spec { ethjson::spec::Engine::InstantSeal => Arc::new(InstantSeal::new(params, builtins)), ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(params, From::from(ethash.params), builtins)), ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)), + ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(params, From::from(authority_round.params), builtins).expect("Consensus engine could not be started."), } } @@ -267,19 +274,17 @@ impl Spec { } /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus. - pub fn new_test() -> Self { - Spec::load(include_bytes!("../../res/null_morden.json") as &[u8]).expect("null_morden.json is invalid") - } + pub fn new_test() -> Spec { load_bundled!("null_morden") } /// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3(''). - pub fn new_null() -> Self { - Spec::load(include_bytes!("../../res/null.json") as &[u8]).expect("null.json is invalid") - } + pub fn new_null() -> Spec { load_bundled!("null") } /// Create a new Spec with InstantSeal consensus which does internal sealing (not requiring work). - pub fn new_test_instant() -> Self { - Spec::load(include_bytes!("../../res/instant_seal.json") as &[u8]).expect("instant_seal.json is invalid") - } + pub fn new_instant() -> Spec { load_bundled!("instant_seal") } + + /// Create a new Spec with AuthorityRound consensus which does internal sealing (not requiring work). + /// Accounts with secrets "1".sha3() and "2".sha3() are the authorities. + pub fn new_test_round() -> Self { load_bundled!("authority_round") } } #[cfg(test)] diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 96d5f8366..adfb4f096 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -433,18 +433,19 @@ pub fn get_default_ethash_params() -> EthashParams{ block_reward: U256::from(0), registrar: "0000000000000000000000000000000000000001".into(), homestead_transition: 1150000, - dao_hardfork_transition: 0x7fffffffffffffff, + dao_hardfork_transition: u64::max_value(), dao_hardfork_beneficiary: "0000000000000000000000000000000000000001".into(), dao_hardfork_accounts: vec![], - difficulty_hardfork_transition: 0x7fffffffffffffff, + difficulty_hardfork_transition: u64::max_value(), difficulty_hardfork_bound_divisor: U256::from(0), - bomb_defuse_transition: 0x7fffffffffffffff, - eip150_transition: 0x7fffffffffffffff, - eip155_transition: 0x7fffffffffffffff, - eip160_transition: 0x7fffffffffffffff, - eip161abc_transition: 0x7fffffffffffffff, - eip161d_transition: 0x7fffffffffffffff, - ecip1010_pause_transition: 0x7fffffffffffffff, - ecip1010_continue_transition: 0x7fffffffffffffff + bomb_defuse_transition: u64::max_value(), + eip150_transition: u64::max_value(), + eip155_transition: u64::max_value(), + eip160_transition: u64::max_value(), + eip161abc_transition: u64::max_value(), + eip161d_transition: u64::max_value(), + ecip1010_pause_transition: u64::max_value(), + ecip1010_continue_transition: u64::max_value(), + max_code_size: u64::max_value(), } } diff --git a/ethcrypto/src/lib.rs b/ethcrypto/src/lib.rs index 103e750e6..c98d14027 100644 --- a/ethcrypto/src/lib.rs +++ b/ethcrypto/src/lib.rs @@ -34,16 +34,43 @@ pub const KEY_LENGTH: usize = 32; pub const KEY_ITERATIONS: usize = 10240; pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2; +#[derive(PartialEq, Debug)] +pub enum ScryptError { + // log(N) < r / 16 + InvalidN, + // p <= (2^31-1 * 32)/(128 * r) + InvalidP, +} + +impl fmt::Display for ScryptError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let s = match *self { + ScryptError::InvalidN => "Invalid N argument of the scrypt encryption" , + ScryptError::InvalidP => "Invalid p argument of the scrypt encryption", + }; + + write!(f, "{}", s) + } +} + #[derive(PartialEq, Debug)] pub enum Error { Secp(SecpError), + Scrypt(ScryptError), InvalidMessage, } +impl From for Error { + fn from(err: ScryptError) -> Self { + Error::Scrypt(err) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { let s = match *self { Error::Secp(ref err) => err.to_string(), + Error::Scrypt(ref err) => err.to_string(), Error::InvalidMessage => "Invalid message".into(), }; @@ -80,13 +107,23 @@ pub fn derive_key_iterations(password: &str, salt: &[u8; 32], c: u32) -> (Vec (Vec, Vec) { +pub fn derive_key_scrypt(password: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec, Vec), Error> { + // sanity checks + let log_n = (32 - n.leading_zeros() - 1) as u8; + if log_n as u32 >= r * 16 { + return Err(Error::Scrypt(ScryptError::InvalidN)); + } + + if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) { + return Err(Error::Scrypt(ScryptError::InvalidP)); + } + let mut derived_key = vec![0u8; KEY_LENGTH]; - let scrypt_params = ScryptParams::new(n.trailing_zeros() as u8, r, p); + let scrypt_params = ScryptParams::new(log_n, r, p); scrypt(password.as_bytes(), salt, &scrypt_params, &mut derived_key); let derived_right_bits = &derived_key[0..KEY_LENGTH_AES]; let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH]; - (derived_right_bits.to_vec(), derived_left_bits.to_vec()) + Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec())) } pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { diff --git a/ethstore/res/wordlist.txt b/ethstore/res/wordlist.txt index f330038cf..caf71f526 100644 --- a/ethstore/res/wordlist.txt +++ b/ethstore/res/wordlist.txt @@ -1,7530 +1,7776 @@ -station -acting -accept -blow -strange -saved -conversation -plane -mama -yesterday -lied -quick -lately -stuck -lovely -security -report -difference -rid -store -bag -bought -ball -single -doubt -listening -major -walking -cops -blue -deep -dangerous -park -sleeping -shh -record -lord -moved -join -key -captain -card -crime -gentlemen -willing -window -return -walked -guilty -likes -fighting -difficult -soul -joke -service -magic -favorite -uncle -promised -public -bother -island -seriously -cell -lead -knowing -broken -advice -somehow -paid -losing -push -helped -killing -usually -earlier -boss -beginning -liked -innocent -doc -rules -summer -cop -learned -thirty -risk -letting -speaking -officer -ridiculous -support -afternoon -born -dreams -apologize -seat -nervous -across -song -charge -patient -boat -brain -hide -detective -general -planning -nine -huge -breakfast -horrible -age -awful -pleasure -driving -hanging -picked -system -sell -quit -apparently -dying -notice -congratulations -chief -faith -gay -month -visit -letter -decide -double -sad -press -forward -fool -showed -smell -seemed -spell -memory -pictures -slow -seconds -hungry -board -position -hearing -kitchen -force -fly -during -space -realized -experience -kick -others -grab -discuss -third -cat -fifty -responsible -miles -fat -reading -idiot -yep -rock -rich -suddenly -agent -bunch -destroy -bucks -track -shoes -scene -peace -arms -demon -low -consider -papers -medical -incredible -witch -drunk -attorney -tells -knock -ways -belle -cash -gives -department -nose -turns -keeps -beer -jealous -drug -sooner -cares -plenty -extra -tea -won -attack -ground -whose -outta -weekend -matters -wrote -type -gosh -opportunity -king -impossible -books -machine -waste -pretend -named -danger -wall -jump -eating -proof -complete -slept -career -arrest -star -breathe -perfectly -warm -pulled -twice -easier -killer -dating -suit -romantic -drugs -comfortable -powers -finds -checked -fit -divorce -begin -ourselves -closer -ruin -although -smile -laugh -fish -treat -fear -otherwise -excited -mail -hiding -cost -green -stole -noticed -fired -excellent -lived -bringing -pop -piper -bottom -note -sudden -church -bathroom -flight -honestly -sing -foot -games -glass -remind -bank -charges -witness -finding -places -tree -dare -hardly -interest -steal -princess -silly -contact -teach -shop -plus -colonel -fresh -trial -invited -roll -radio -art -reach -heh -dirty -choose -emergency -dropped -butt -credit -obvious -cry -locked -loving -positive -nuts -agreed -price -goodbye -condition -guard -grow -cake -mood -total -crap -crying -belong -lay -partner -trick -pressure -ohh -arm -dressed -cup -lies -bus -taste -neck -south -nurse -raise -land -cross -lots -mister -carry -group -whoever -drinking -breaking -file -lock -computer -wine -closed -writing -spot -paying -study -assume -asleep -turning -legal -justice -bedroom -shower -camera -fill -reasons -forty -bigger -nope -keys -breath -doctors -pants -freak -level -movies -gee -action -area -folks -cream -ugh -continue -focus -wild -truly -desk -convince -client -threw -band -hurts -spending -field -allow -grand -answers -shirt -chair -allowed -rough -doin -sees -government -ought -empty -round -lights -insane -hall -hat -bastard -wind -shows -aware -dealing -pack -meaning -flowers -tight -hurting -ship -subject -guest -chicken -pal -match -arrested -sun -confused -surgery -expecting -deacon -unfortunately -goddamn -lab -passed -bottle -beyond -whenever -pool -opinion -naked -held -common -starts -jerk -secrets -falling -played -necessary -barely -dancing -health -tests -copy -video -cousin -planned -dry -ahem -twelve -simply -skin -often -fifteen -spirit -speech -names -issue -orders -nah -final -results -code -believed -complicated -umm -research -nowhere -escape -biggest -restaurant -page -grateful -usual -burn -address -within -someplace -screw -everywhere -train -film -regret -goodness -mistakes -heaven -details -responsibility -suspect -corner -hero -dumb -terrific -mission -further -gas -whoo -hole -memories -truck -following -ended -teeth -ruined -split -bear -airport -bite -smoke -older -liar -horse -showing -van -project -cards -desperate -themselves -search -pathetic -damage -spoke -quickly -scare -beach -brown -afford -vote -settle -gold -mentioned -due -passion -stayed -rule -checking -tie -hired -upon -rush -heads -concern -blew -natural -champagne -connection -tickets -finger -happiness -form -saving -kissing -hated -personally -suggest -prepared -build -leg -onto -leaves -downstairs -ticket -taught -loose -holy -staff -sea -planet -duty -convinced -throwing -defense -kissed -legs -according -loud -practice -bright -babies -army -warning -miracle -carrying -flying -blind -queen -ugly -shopping -hates -monster -sight -vampire -bride -coat -account -states -clearly -celebrate -brilliant -wanting -add -moon -lips -custody -center -screwed -buying -size -toast -thoughts -student -stories -however -professional -stars -reality -birth -attitude -advantage -grandfather -sold -opened -grandma -beg -changes -someday -grade -cheese -roof -pizza -brothers -signed -bird -ahh -marrying -powerful -grown -grandmother -fake -opening -expected -eventually -ideas -exciting -covered -familiar -bomb -television -harmony -color -heavy -schedule -records -dollar -capable -master -numbers -practically -including -correct -clue -forgotten -immediately -appointment -social -nature -รบ -deserves -west -teacher -threat -bloody -lonely -ordered -shame -local -jacket -hook -destroyed -scary -loser -investigation -above -invite -shooting -merry -port -precious -lesson -criminal -growing -caused -victim -professor -followed -funeral -dean -considering -burning -couch -strength -harder -loss -view -beauty -sisters -several -pushed -written -shock -pushing -heat -chocolate -greatest -miserable -nightmare -energy -brings -character -became -famous -enemy -crash -chances -sending -recognize -healthy -boring -feed -engaged -percent -headed -lines -treated -purpose -north -knife -rights -drag -fan -badly -speed -hire -curious -paint -pardon -built -behavior -closet -candy -warn -gorgeous -post -milk -survive -forced -daria -victoria -operation -suck -offered -ends -dump -rent -marshall -remembered -lieutenant -trade -thanksgiving -rain -revenge -physical -available -program -prefer -spare -pray -disappeared -aside -statement -sometime -animal -sugar -meat -fantastic -breathing -laughing -itself -tip -stood -market -affair -ours -depends -cook -babe -main -woods -protecting -jury -national -brave -storm -large -prince -interview -roger -football -fingers -murdered -sexy -explanation -process -picking -based -style -stone -pieces -blah -assistant -stronger -block -aah -bullshit -pie -handsome -unbelievable -anytime -nearly -shake -cars -wherever -serve -pulling -points -medicine -facts -waited -lousy -circumstances -stage -disappointed -weak -trusted -license -nothin -community -trey -trash -understanding -slip -cab -sounded -awake -friendship -stomach -weapon -threatened -mystery -official -dick -regular -river -valley -understood -contract -bud -sexual -race -basically -switch -lake -frankly -issues -cheap -lifetime -deny -painting -ear -clock -baldwin -weight -garbage -tear -ears -dig -bullet -selling -setting -indeed -gus -changing -singing -tiny -particular -draw -decent -susan -super -spring -santos -avoid -messed -united -filled -touched -score -disappear -stranger -exact -pills -kicked -harm -recently -snow -fortune -strike -pretending -raised -annie -slayer -monkey -insurance -fancy -sydney -drove -cared -belongs -nights -shape -dogs -lorelai -jackie -base -maggie -lift -lewis -stock -fashion -freedom -timing -johnny -guarantee -chest -bridge -woke -tabitha -source -patients -theory -lisa -camp -original -juice -burned -access -watched -heading -selfish -oil -drinks -wise -failed -period -doll -committed -elevator -freeze -noise -exist -science -pair -edge -wasting -sat -player -ceremony -cartman -pig -uncomfortable -peg -guns -vacation -staring -files -bike -weather -mostly -stress -sucks -permission -arrived -thrown -possibility -faster -example -borrow -release -ate -notes -joy -hoo -library -junior -property -negative -fabulous -event -doors -screaming -vision -member -bone -battle -safety -term -devil -meal -fellow -asshole -apology -anger -honeymoon -wet -bail -parking -fucked -non -hung -protection -manager -fixed -families -dawn -sports -campaign -map -wash -stolen -sensitive -stealing -photo -chose -lets -comfort -worrying -whom -pocket -bleeding -students -shoulder -ignore -fourth -neighborhood -talent -tied -garage -dies -demons -travel -success -dumped -witches -training -rude -crack -model -bothering -radar -grew -willow -remain -soft -meantime -gimme -connected -chase -kinds -cast -cancer -v -sky -likely -fate -buried -hug -driver -concentrate -throat -prom -messages -east -unit -intend -crew -ashamed -somethin -midnight -manage -guilt -weapons -terms -interrupt -guts -tongue -distance -conference -treatment -shoe -basement -sentence -purse -glasses -cabin -universe -towards -repeat -mirror -wound -tall -reaction -odd -engagement -therapy -letters -emotional -runs -magazine -jeez -decisions -soup -thrilled -society -managed -sue -stake -rex -chef -moves -awesome -genius -extremely -entirely -tory -nasty -moments -expensive -counting -shots -kidnapped -square -cleaning -shift -plate -impressed -smells -trapped -male -tour -knocked -charming -attractive -argue -puts -whip -language -heck -embarrassed -settled -package -laid -animals -hitting -disease -bust -stairs -alarm -pure -nail -nerve -incredibly -hill -walks -lane -dirt -bond -stamp -becoming -terribly -friendly -easily -damned -jobs -suffering -disgusting -washington -stopping -deliver -riding -helps -federal -disaster -bars -crossed -rate -create -trap -claim -talks -eggs -effect -chick -turkey -threatening -spoken -snake -introduce -rescue -confession -embarrassing -bags -lover -impression -gate -fantasy -reputation -balls -attacked -among -knowledge -presents -inn -chat -suffer -bryant -argument -talkin -crowd -homework -fought -coincidence -cancel -accepted -rip -pride -solve -hopefully -pounds -pine -mate -illegal -generous -tommy -streets -matt -director -glen -con -separate -outfit -maid -bath -punch -phil -mayor -helen -freaked -begging -recall -enjoying -bug -prepare -parts -wheel -signal -nikki -direction -defend -signs -painful -caroline -yourselves -walls -rat -maris -amount -suspicious -hearts -flat -cooking -button -warned -sixty -pity -parties -crisis -rae -coach -abbott -row -baseball -yelling -leads -awhile -pen -confidence -offering -falls -carter -image -farm -pleased -panic -monday -hers -gettin -smith -role -refuse -determined -jane -grandpa -progress -mexico -testify -passing -military -choices -artist -william -uhh -gym -cruel -wings -traffic -pink -bodies -mental -gentleman -coma -poison -cutting -proteus -guests -expert -bull -benefit -bell -faces -cases -mimi -ghost -led -jumped -toilet -secretary -sneak -q -mix -marty -firm -agreement -privacy -dates -anniversary -smoking -reminds -pot -created -twins -swing -successful -season -scream -considered -solid -options -flash -commitment -senior -ill -crush -ambulance -wallet -discovered -officially -gang -til -rise -reached -eleven -option -laundry -former -assure -stays -skip -hunt -fail -accused -wide -challenge -popular -learning -discussion -clinic -plant -exchange -betrayed -bro -sticking -university -target -members -lower -bored -mansion -soda -silver -sheriff -suite -handled -busted -senator -load -happier -younger -studying -romance -procedure -ocean -section -winter -sec -commit -bones -assignment -suicide -spread -minds -fishing -swim -ending -bat -yell -llanview -league -chasing -seats -proper -holiday -command -believes -humor -hopes -fifth -winning -solution -leader -yellow -sharp -sale -lawyers -giant -nor -material -latest -ash -highly -escaped -audience -winner -parent -burns -tricks -insist -dropping -cheer -medication -higher -flesh -district -wood -routine -cookies -century -shared -sandwich -psycho -handed -false -beating -appear -adult -warrant -spike -garden -awfully -odds -article -treating -thin -suggesting -fever -female -sweat -silent -specific -clever -sweater -request -prize -mall -tries -mile -manning -fully -estate -diamond -union -sharing -assuming -judgment -goodnight -divorced -quality -despite -surely -steps -jet -confess -mountain -math -listened -comin -answered -vulnerable -bless -dreaming -rooms -chip -zero -potential -pissed -kills -grant -wolf -tears -knees -chill -blonde -brains -agency -degree -unusual -joint -rob -packed -dreamed -cure -covering -newspaper -lookin -coast -grave -egg -direct -cheating -breaks -quarter -orange -mixed -locker -gifts -brand -awkward -toy -rare -policy -pilar -joking -competition -classes -assumed -reasonable -dozen -curse -quartermaine -millions -dessert -rolling -detail -alien -served -delicious -closing -vampires -released -ancient -wore -value -tail -site -secure -salad -murderer -hits -toward -spit -screen -pilot -penny -offense -dust -conscience -bread -answering -admitted -lame -invitation -hidden -grief -smiling -path -homer -destiny -del -stands -bowl -pregnancy -prisoner -delivery -guards -desire -virus -shrink -influence -freezing -concert -wreck -partners -chain -birds -walker -wire -technically -presence -blown -anxious -cave -version -mickey -holidays -cleared -wishes -survived -caring -candles -bound -related -charm -apple -yup -pulse -jumping -jokes -frame -boom -vice -performance -occasion -silence -opera -opal -nonsense -frightened -downtown -internet -slipped -holly -duck -dimera -blowing -session -relationships -kidnapping -actual -spin -classic -civil -tool -packing -education -blaming -wrap -obsessed -fruit -torture -personality -location -loan -effort -commander -trees -rocks -owner -fairy -banks -network -per -necessarily -county -contest -chuck -seventy -print -motel -fallen -directly -underwear -grams -exhausted -believing -particularly -freaking -carefully -trace -touching -messing -committee -smooth -recovery -intention -enter -consequences -belt -standard -sacrifice -marina -courage -butter -officers -enjoyed -lack -buck -attracted -appears -bay -yard -returned -remove -nut -carried -testimony -intense -granted -violence -heal -defending -attempt -unfair -relieved -political -loyal -approach -slowly -plays -normally -buzz -alcohol -actor -surprises -psychiatrist -pre -plain -attic -uniform -terrified -sons -pet -cleaned -threaten -teaching -mum -motion -fella -enemies -desert -collection -incident -failure -satisfied -imagination -hooked -headache -forgetting -counselor -acted -opposite -highest -gross -golden -equipment -badge -tennis -visiting -studio -naturally -frozen -commissioner -sakes -labor -glory -appropriate -trunk -armed -twisted -thousands -received -dunno -costume -temporary -sixteen -impressive -zone -kitty -kicking -junk -hon -grabbed -unlike -understands -mercy -describe -priest -clients -cable -owns -affect -witnesses -starving -instincts -happily -discussing -deserved -strangers -leading -intelligence -host -authority -surveillance -cow -commercial -admire -shadow -questioning -fund -dragged -barn -object -deeply -amp -wrapped -wasted -tense -sport -route -reports -plastic -hoped -fellas -election -roommate -pierce -mortal -fascinating -chosen -stops -shown -arranged -abandoned -sides -delivered -china -becomes -arrangements -agenda -hunting -began -theater -series -literally -propose -honesty -basketball -underneath -forces -soldier -services -sauce -review -promises -lecture -eighty -brandy -bills -windows -torn -shocked -relief -horses -golf -explained -counter -design -circle -victims -transfer -response -channel -backup -identity -differently -campus -spy -ninety -interests -guide -elliot -deck -biological -pheebs -minor -ease -creep -waitress -skills -telephone -photos -ripped -raising -scratch -rings -prints -flower -wave -thee -arguing -royal -laws -figures -asks -writer -reception -pin -oops -diner -annoying -agents -taggert -goal -council -mass +abacus +abdomen +abdominal +abide +abiding ability -sergeant -international -gig -blast -basic -wing -tradition -towel -earned -clown -rub -habit -customers -creature -counts -actions -snap -react -prime -paranoid -pace -wha -handling -eaten -dahlia -therapist -comment -charged -tax -sink -reporter -nurses -beats -priority -interrupting -gain -fed -warehouse -virgin -shy -pattern -loyalty -inspector -events -candle -pleasant -media -excuses -duke -castle -threats -permanent -guessing -financial -demand -basket -assault -tend -praying -motive -los -unconscious -trained -museum -alley -tracks -swimming -range -nap -mysterious -unhappy -tone -switched -liberty -bang -award -neighbor -loaded -gut -childhood -causing -swore -sample -piss -hundreds -balance -background -toss -mob -misery -central -boots -thief -squeeze -potter -lobby -hah -geez -exercise -ego -drama -patience -noble -indian -forth -facing -engine -booked -boo -songs -poker -eighteen -cookie -bury -perform -everyday -digging -creepy -compared -wondered -trail -saint -rotten -liver -hmmm -drawn -device -whore -magical -village -march -journey -fits -discussed -zombie -supply -moral -helpful -attached -slut -searching -flew -depressed -aliens -aisle -underground -pro -drew -daughters -cris -amen -vows -proposal -pit -neighbors -darn -clay -cents -arrange -annulment -uses -useless -squad -represent -product -joined -afterwards -adventure -resist -protected -net -fourteen -celebrating -piano -inch -flag -debt -darkness -violent -tag -sand -gum -dammit -strip -hip -celebration -below -reminded -palace -claims -replace -phones -paperwork -mighty -emotions -typical -stubborn -stable -pound -pillow -papa -mature -lap -designed -current -bum -tension -tank -suffered -stroke -steady -provide -overnight -meanwhile -chips -beef -wins -suits -carol -boxes -salt -express -collect -tragedy -therefore -spoil -realm -profile -degrees -wipe -surgeon -stretch -stepped -nephew -neat -limo -fox -confident -anti -victory -perspective -designer -climb -angels -title -suggested -punishment -finest -occurred -hint -furniture -blanket -twist -trigger -surrounded -surface -proceed -lip -jersey -fries -worries -refused -niece -handy -gloves -soap -signature -disappoint -crawl -convicted -zoo -result -pages -lit -flip -counsel -cheers -doubts -crimes -accusing -shaking -remembering -phase -kit -hallway -halfway -bothered -useful -popcorn -makeup -madam -gather -cowboy -concerns -cameras -blackmail -symptoms -rope -ordinary -imagined -concept -cigarette -barb -supportive -memorial -explosion -yay -woo -trauma -ouch -furious -cheat -avoiding -whew -thick -oooh -boarding -approve -urgent -shhh -misunderstanding -minister -drawer -sin -phony -joining -jam -interfere -governor -chapter -catching -bargain -warren -tragic -schools -respond -punish -penthouse -hop -angle -thou -sherry -remains -rach -ohhh -insult -bugs -beside -begged -absolute -strictly -socks -senses -ups -sneaking -yah -worthy -serving -reward -polite -checks -tale -physically -instructions -fooled -blows -tabby -internal -bitter -adorable -tested -suggestion -string -mouse -marks -jewelry -debate -com -alike -pitch -jacks -fax -distracted -shelter -lovers -lessons -hart -goose -foreign -escort -average -twin -testing -damnit -constable -circus -audition -tune -shoulders -mud -mask -helpless -feeding -explains -dated -sucked -robbery -objection -kirk -behave -valuable -shadows -creative -courtroom -confusing -beast -tub -talented -struck -smarter -mistaken -customer -bizarre -scaring -punk -motherfucker -holds -focused -alert -activity -vecchio -sticks -singer -reverend -highway -foolish -compliment -blessed -bastards -attend -scheme -aid -worker -wheelchair -protective -poetry -gentle -script -reverse -picnic -knee -intended -construction -cage -wives -voices -toes -stink -scares -pour -effects -cheated -tower -slide -ruining -recent -jewish -filling -exit -cruise -cottage -corporate -cats -upside -supplies -proves -parked -instance -grounds -diary -complaining -basis -wounded -politics -confessed -wicked -pipe -merely -massage -data -colors -chop -budget -brief -spill -prayer -costs -chicks -betray -begins -arrangement -waiter -sucker -scam -rats -fraud -flu -brush -adopted -tables -sympathy -pill -pee -lean -filthy -cliff -burger -web -seventeen -landed -expression -entrance -employee -drawing -cap -bunny -bracelet -thirteen -scout -principal -pays -fairly -facility -deeper -arrive -unique -tracking -spite -shed -recommend -oughta -nanny -naive -menu -grades -diet -corn -authorities -separated -roses -patch -grey -dime -devastated -description -tap -subtle -include -garrison -citizen -bullets -beans -pile -metal -las -executive -confirm -capital -adults -toe -strings -parade -harbor -bow -borrowed -booth -toys -straighten -steak -status -remote -premonition -poem -planted -honored -youth -specifically -meetings -exam -daily -convenient -traveling -matches -laying -insisted -crystal -apply -units -technology -steel -muscle -dish -aitoro -sis -sales -legend -kindly -grandson -donor -wheels -temper -teenager -strategy -proven -mothers -monitor -iron -houses -eternity -denial -couples -backwards -tent -swell -noon -happiest -gotcha -episode -drives -bacon -thinkin -spirits -potion -holes -fence -dial -affairs -acts -whatsoever -ward -rehearsal -proved -overheard -nuclear -lemme -leather -hostage -hammer -faced -discover -constant -bench -tryin -taxi -shove -sets -moron -limits -impress -gray -entitled -connect -pussy -needle -limit -lad -intelligent -instant -forms -disagree -tiger -stinks -recover -losers -groom -gesture -developed -constantly -blocks -bartender -tunnel -suspects -sealed -removed -paradise -legally -illness -hears -dresses -aye -vehicle -thy -teachers -sheet -receive -psychic -denied -teenage -rabbit -puppy -knocking -judging -bible -behalf -accidentally -waking -ton -superior -slack -seek -rumor -manners -homeless -hollow -hills -desperately -critical -coward -theme -tapes -sheets -referring -personnel -item -gear -majesty -forest -fans -exposed -cried -tons -spells -producer -launch -jay -instinct -extreme -belief -quote -motorcycle -convincing -appeal -advance -greater -fashioned -empire -aids -accomplished -grip -bump -upsetting -soldiers -scheduled -production -needing -invisible -forgiveness -feds -complex -compare -cloud -champion -bothers -blank -treasure -tooth -territory -sacred -inviting -inner -earn -compromise -cocktail -tramp -temperature -signing -messenger -landing -jabot -intimate -dignity -dealt -souls -root -informed -gods -entertainment -dressing -cigarettes -blessing -billion -upper -manner -lightning -leak -fond -alternative -seduce -players -operate -modern -liquor -fingerprints -enchantment -butters -stuffed -filed -emotionally -division -conditions -uhm -transplant -tips -powder -passes -oxygen -nicely -lunatic -hid -drill -designs -complain -announcement -visitors -unfortunate -slap -pumpkin -prayers -plug -organization -opens -oath -mutual -hockey -graduate -confirmed -broad -yacht -spa -remembers -horn -fried -extraordinary -bait -appearance -abuse -sworn -stare -safely -reunion -plot -burst -aha -experiment -experienced -dive -commission -chaos -cells -aboard -returning -lesbian -independent -expose -environment -buddies -trusting -spider -smaller -mountains -booze -tattoo -sweep -sore -scudder -properly -parole -effective -ditch -decides -canceled -bulldog -bra -speaks -rubber -reaching -glow -foundation -wears -thirsty -skull -scotch -ringing -dorm -dining -bend -unexpected -systems -sob -pat -pancakes -harsh -flattered -existence -ahhh -troubles -proposed -fights -favourite -eats -driven -computers -chin -bravo -seal -rage -causes -bubble -border -undercover -spoiled -shine -rug -identify -destroying -deputy -deliberately -conspiracy -clothing -thoughtful -similar -sandwiches -plates -nails -miracles -investment -fridge -drank -contrary -beloved -allergic -washed -stalking -solved -sack -misses -forgiven -earl -cuz -bent -approval -practical -organized -jungle -involve -industry -fuel -dragging -dancer -cotton -cooked -possession -pointing -foul -editor -dull -beneath -ages -peanut -horror -heels -grass -faking -deaf -stunt -portrait -painted -jealousy -hopeless -fears -cuts -conclusion -volunteer -sword -scenario -satellite -necklace -crashed -chapel -accuse -teddy -restraining -naughty -humans -homicide -helicopter -formal -firing -shortly -safer -missy -diamonds -devoted -auction -videotape -tore -stores -reservations -pops -appetite -wounds -vanquish -symbol -prevent -patrol -ironic -flow -fathers -excitement -anyhow -tearing -sends -rape -laughed -function -core -charmed -carpet -bowling -belly -sub -shark -dealer -cooperate -bachelor -accomplish -wakes -struggle -spotted -sorts -reservation -fort -coke -ashes -yards -votes -tastes -supposedly -loft -intentions -integrity -wished -towels -suspected -slightly -qualified -profit -log -investigating -inappropriate -immediate -ginger -companies -backed -sunset -pan -owned -nation -lipstick -lawn -compassion -cafeteria -belonged -affected -scarf -precisely -obsession -management -loses -lighten -infection -granddaughter -explode -chemistry -balcony -storage -spying -publicity -exists -employees -depend -cue -cracked -conscious -aww -ally -ace -accounts -absurd -vicious -tools -strongly -rap -potato -invented -hood -forbid -directions -defendant -bare -announce -screwing -samples -salesman -rounds -robbed -leap -lakeview -insanity -injury -genetic -freaks -fighter -document -burden -swallow -slave -reveal -religious -possibilities -martini -kidnap -gown -entering -chairs -wishing -statue -stalker -setup -serial -sandy -punished -dramatic -dismissed -criminals -carver -blade -seventh -regrets -raped -quarters -produce -pony -lamp -dentist -anyways -anonymous -added -tech -semester -risks -regarding -owes -magazines -machines -lungs -explaining -delicate -tricked -oldest -eager -doomed -coffin -click -cafe -buttons -bureau -adoption -traditional -surrender -stones -stab -sickness -scum -loop -independence -generation -floating -envelope -entered -combination -chamber -casino -worn -vault -sunshine -sorel -pretended -potatoes -plea -photograph -petty -payback -misunderstood -kiddo -healing -fiancรฉe -cascade -capeside -application -stabbed -remarkable -random -guitar -frog -cabinet -brat -wrestling -sixth -scale -privilege -pencil -passionate -nerves -lawsuit -kidney -disturbed -crossing -cozy -avatar -associate -tire -shirts -required -posted -oven -ordering -mill -journal -gallery -delay -clubs -risky -purple -nest -monsters -honorable -grounded -gene -favour -electric -culture -closest -breast -breakdown -attempted -placed -conflict -bald -actress -abandon -wisdom -steam -scar -pole -duh -collar -worthless -warlock -sucking -standards -resources -photographs -introduced -injured -graduation -enormous -disturbing -disturb -distract -deals -conclusions -baker -vodka -situations -require -muffin -mid -measure -dishes -crawling -congress -briefcase -wiped -whistle -sits -roast -rented -pigs -penis -massive -link -flirting -existed -deposit -damaged -bottles -unknown -types -topic -robin -riot -overreacting -minimum -logical -impact -hostile -embarrass -casual -beacon -amusing -altar -values -ultimate -skinny -recognized -maintain -goods -covers -battery -survival -skirt -shave -prisoners -porch -med -ghosts -favors -drops -dizzy -chili -breasts -begun -beaten -advise -transferred -strikes -rehab -raw -photographer -peaceful -leery -kraft -hooker -heavens -fortunately -fooling -expectations -draft -citizens -cigar -active -weakness -ski -ships -ranch -practicing -musical -movement -individual -homes -executed -examine -documents -cranes -column -bribe -beers -task -species -sail -rum -resort -rash -prescription -operating -hush -fuzzy -fragile -forensics -expense -drugged -differences -cows -conduct -comic -bingo -bells -avenue -attacking -assigned -visitor -suitcase -sources -sorta -scan -rod -payment -motor -mini -manticore -inspired -insecure -imagining -hardest -gamble -clerk -yea -wrist -tube -starters -silk -pump -pale -nicer -haul -guardian -flies -dodge -demands -boot -arts -thumb -limited -lighter -elders -connections -shooter -quietly -pulls -lion -idiots -factor -erase -denying -attacks -ankle -amnesia -accepting -ooo -hunter -heartbeat -gal -fry -confront -backing -register -phrase -operations -minus -meets -legitimate -hurricane -fixing -communication -bucket -boats -auto -arrogant -tuna -supper -studies -slightest -sins -sayin -recipe -pier -paternity -mason -lamb -kisses -humiliating -genuine -catholic -snack -rational -pointed -passport -minded -guessed -fiancรฉ -display -dip -advanced -weddings -unh -tumor -teams -reported -marco -humiliated -hee -destruction -copies -closely -bid -banana -august -aspirin -academy -wig -throughout -spray -picks -occur -logic -knight -fields -eyed -equal -drowning -contacts -ritual -perfume -hiring -hating -ham -generally -fusion -error -elected -docks -creatures -visions -thanking -thankful -sock -replaced -reed -nineteen -fork -comedy -analysis -throws -teenagers -studied -stressed -slice -shore -rolls -requires -plead -palm -ladder -kicks -ford -detectives -assured -widow -tissue -tellin -shallow -responsibilities -repay -rejected -permanently -howdy -hack -girlfriends -deadly -comforting -ceiling -bonus -verdict -maintenance -jar -insensitive -heather -factory -aim -triple -spilled -respected -recovered -messy -interrupted -entry -blond -bleed -benefits -wardrobe -takin -significant -objective -murders -foster -doo -ding -chart -backs -airplane -workers -waves -underestimate -ties -soccer -registered -multiple -justify -harmless -frustrated -fold -convention -communicate -bugging -attraction -arson -whack -tits -salary -rumors -residence -obligation -medium -liking -development -develop -dearest -congratulate -alliance -vengeance -severe -rack -puzzle -puerto -guidance -fires -dickie -courtesy -caller -bounce -blamed -wizard -tops -repair -quiz -prep -involves -headquarters -curiosity -codes -circles -bears -barbecue -troops -spinning -scores -pursue -psychotic -groups -cough -claimed -accusations -shares -rushing -resent -laughs -gathered -freshman -envy -drown -chemical -branch -asses -sofa -scientist -poster -models -islands -highness -drain -dock -cha -apologies -welfare -theirs -stat -stall -spots -somewhat -solo -realizes -psych -mmmm -jazz -hawk -fools -finishing -beard -album -wee -understandable -unable -treats -theatre -succeed -stir -relaxed -makin -inches -gratitude -faithful -bin -accent -zip -witter -wandering -shell -regardless -racing -que -locate -inevitable -griffin -deed -crushed -controlling -western -taxes -smelled -sheep -settlement -rocky -robe -retired -poet -opposed -marked -gossip -gambling -determine -cosmetics -cent -accidents -tricky -surprising -stiff -sincere -shield -rushed -rice -resume -reporting -refrigerator -reference -preparing -nightmares -mijo -ignoring -hunch -fog -fireworks -drowned -crown -cooperation -brass -accurate -whispering -sophisticated -religion -luggage -lemon -investigate -hike -explore -emotion -dragon -creek -crashing -contacted -complications -cherry -acid -z -shining -rolled -righteous -reconsider -inspiration -goody -geek -frightening -festival -ethics -creeps -courthouse -camping -assistance -affection -vow -protest -lodge -haircut -forcing -eternal -essay -chairman -baked -apologized -vibe -stud -stargate -sailor -respects -receipt -operator -mami -includes -hats -goat -exclusive -destructive -define -defeat -cheek -adore -adopt -warrior -voted -tracked -signals -shorts -reminding -relative -pond -ninth -floors -dough -creations -continues -cancelled -barrel -tuck -snuck -slight -reporters -rear -pressing -novel -newspapers -magnificent -madame -lick -lazy -goddess -glorious -fiancee -candidate -brick -bits -activities -visitation -teen -scholarship -sane -previous -kingdom -kindness -flames -sunny -shoulda -rescued -mattress -lounge -lobster -lifted -label -importantly -glove -enterprises -disappointment -condo -cemetery -beings -admitting -yelled -waving -spoon -screech -satisfaction -requested -reads -plants -nun -navy -nailed -elephant -described -dedicated -certificate -centuries -annual -worm -tick -resting -primary -polish -monkeys -marvelous -fuss -funds -defensive -compete -chased -bush -balloon -sailing -provided -pockets -filing -depression -conversations -consideration -consciousness -worlds -innocence -indicate -fucker -freaky -forehead -bam -appeared -aggressive -trailer -summers -slam -retirement -quitting -pry -porn -narrow -levels -inform -fee -encourage -dug -delighted -daylight -danced -currently -confidential -chew -aunts -washing -warden -tossed -temple -spectra -permit -mistress -marrow -lined -implying -hatred -grill -formula -efforts -corpse -clues -sober -relatives -promotion -peel -offended -morgue -larger -infected -humanity -eww -electricity -electrical -distraction -chopper -cart -broadcast -wired -violation -suspended -sting -promising -harassment -glue -gathering -deer -cursed -controlled -content -combat -calendar -brutal -bing -assets -warlocks -wagon -unpleasant -tan -robot -proving -priorities -pepper -observation -lease -killers -grows -flame -domestic -divine -disappearance -depressing -thrill -terminal -sitter -ribs -offers -naw -flush -exception -earrings -deadline -corporal -collapsed -update -snapped -smack -offices -melt -madness -figuring -eagle -delusional -coulda -burnt -actors -trips -tender -sperm -specialist -scientific -satan -realise -pork -popped -planes -interrogation -institution -included -gates -esteem -communications -choosing -choir -undo -pres -prayed -plague -manipulate -lifestyle -lance -insulting -honour -detention -delightful -daisy -coffeehouse -chess -betrayal -apologizing -adjust -wrecked -wont -whipped -rides -reminder -psychological -principle -monsieur -injuries -fame -faint -confusion -clouds -bon -bake -sang -nearest -industries -illusion -execution -distress -definition -cutter -creating -correctly -complaint -chickens -blocked -trophy -tortured -structure -rot -risking -pointless -pearl -household -heir -handing -eighth -dumping -cups -alibi +ablaze +able +abnormal +abrasion +abrasive +abreast +abridge +abroad +abruptly absence -vital -towers -thus -struggling -shiny -risked -refer -mummy -mint -keeper -involvement -hose -hobby -fortunate -fitting -curtain -counseling -coats -addition -wit -transport -technical -rode -puppet -prior -opportunities -modeling -memo -liquid -irresponsible -humiliation -hiya -freakin -fez -felony -choke -blackmailing -appreciated -tabloid -suspicion -recovering -rally -psychology -pledge -panicked -nursery -louder -jeans -investigator -identified -homecoming -height -graduated -frustrating -fabric -dot -distant -cock -buys -busting -buff -wax -sleeve -pudding -products -philosophy -japan -irony -hospitals -dope -declare -autopsy -workin -torch -substitute -scandal -prick -limb -leaf -laser -hysterical -growth -goddamnit -fetch -dimension -crowded -cousins -clip -climbing -bonding -bee -approved -yeh -woah -veronica -ultimately -trusts -terror -roller -returns -negotiate -millennium -marsh -majority -lethal -length -iced -fantasies -element -deeds -cigars -bore -babysitter -sponge -sleepy -questioned -peek -outrageous -nigger -medal -insulted -grudge -established -driveway -deserted -definite -capture -beep -wires -weed -suggestions -searched -owed -originally -nickname -lighting -lend -films -drunken -demanding -conviction -characters -bumped -weigh -weasel -valentine -touches -tempted -supreme -shout -rocket -resolve -relate -poisoned -pip -occasionally -meals -maker -invitations -intruder -haunted -fur -footage -depending -bonds -bogus -autograph -apples -affects -tolerate -stepping -spontaneous -southern -sleeps -probation -presentation -performed -identical -herb -fist -cycle -cooler -banner -associates -yankee -streak -spectacular -sector -muscles -lasted -increase -hostages -heroin -havin -hardware -habits -fisher -encouraging -cult -consult -burgers -boyfriends -bailed -baggage -association -wealthy -watches -versus -troubled -torturing -teasing -sweetest -stations -sip -rag -qualities -postpone -pad -overwhelmed -maniac -impulse -hut -follows -duchess -classy -charging -celebrity -amazed -slater -scenes -rising -revealed -representing -policeman -offensive -mug -hypocrite -humiliate -hideous -hairy -finals -experiences -courts -costumes -captured -bolt -bluffing -betting -bein -bedtime -alpha -alcoholic -waters -visual -vegetable -tray -suspicions -sticky -spreading -splendid -smiles -shrimp -shouting -roots -ransom -pressed -nooo -jew -intent -grieving -gladly -fling -eliminate -disorder -cocaine -chancellor -cereal -arrives -aaah -yum -technique -subway -strain -statements -sonofabitch -servant -roads -resident -republican -paralyzed -orb -lotta -locks -guaranteed -dummy -discipline -despise -dental -corporation -cherish -carries -briefing -bluff -batteries -atmosphere -assholes -whatta -tux -sounding -servants -rifle -presume -mamie -handwriting -goals -gin -gale -fainted -elements -dried -cape -allright -allowing -acknowledge -whiskey -whacked -toxic -skating -shepherd -reliable -quicker -penalty -panel -overwhelming -nearby -lining -importance -ike -harassing -global -fatal -endless -elsewhere -dolls -convict -butler -bold -ballet -รฑ -whatcha -unlikely -spiritual -shutting -separation -rusty -recording -positively -overcome -mount -method -manual -helmet -goddam -failing -essence -dose -diagnosis -cured -claiming -bully -airline -ahold -yearbook -various -triangle -tempting -shelf -rig -pursuit -prosecution -pouring -possessed -partnership -november -humble -greedy -countries -wonders -tsk -thorough -spine -shotgun -reckless -railroad -psychiatric -meaningless -latte -jammed -ignored -fiance -exposure -exhibit -evidently -duties -contempt -compromised -capacity -cans -weekends -urge -thunder -theft -suing -shipment -scissors -responding -refuses -proposition -porter -noises -matching -marine -located -leon -legacy -ink -hormones -hail -grandchildren -godfather -gently -establish -eastern -darryl -contracts -compound -worldwide -smashed -sexually -sentimental -senor -scored -nicest -marketing -manipulated -jaw -intern -handcuffs -framed -errands -entertaining -discovery -crib -carriage -barge -awards -attending -ambassador -videos -tab -spends -slipping -seated -rubbing -rely -reject -recommendation -reckon -ratings -headaches -float -embrace -corners -whining -turner -sweating -sole -skipped -rolf -restore -receiving -population -pep -olive -mountie -motives -listens -jeep -heroes -controls -cleaner -cheerleader -wooden -unnecessary -stunning -slim -shipping -scent -quest -praise -pose -luxury -loosen -info -hum -hottest -haunt -gracious -git -forgiving -fleet -errand -emperor -cakes -blames -abortion -worship -theories -strict -sketch -shifts -plotting -physician -perimeter -passage -pals -mere -meg -mattered -longest -jews -interference -grease -eyewitness -enthusiasm -encounter -diapers -artists -strongest -shaken -serves -punched -projects -portal -outer -nazi -jewels -concrete -colleagues -catches -carrot -bearing -backyard -academic -winds -whisper -volume -terrorists -sabotage -pope -pea -organs -needy -mock -mentor -measures -listed -lex -cuff -civilization -breeze -articles -yummy -writes -woof -valid -skipper -sands -rarely -rabbi -prank -performing -obnoxious -mates -improve -hereby -gabby -faked -cheeks -cellar -whitelighter -void -trucks -tomato -substance -strangle -sour -skill -senate -purchase -native -muffins -maximum -interfering -hoh -fiction -exotic -demonic -colored -clearing -civilian -buildings -brooks -boutique -winters -trading -terrace -speaker -smoked -skiing -seed -righty -relations -quack -published -preliminary -pact -outstanding -opinions -knot -ketchup -items -examined -disappearing -coin -circuit -assist -administration -violet -uptight -ticking -terrifying -tease -swamp -secretly -rejection -reflection -realizing -rays -partly -mentally -jurisdiction -doubted -deception -crucial -congressman -cheesy -chambers -bitches -arrival -visited -toto -supporting -stalling -shook -scouts -scoop -ribbon -reserve -raid -notion -income -immune -hay -expects -edition -destined -constitution -classroom -boobs -bets -bathing -appreciation -appointed -accomplice -wander -shoved -sewer -seeking -scroll -retire -peach -paintings -nude -lasts -fugitive -freezer -discount -cranky -crank -clowns -clearance -buffalo -bodyguard -anxiety -accountant -whoops -volunteered -terrorist -tales -talents -stinking -snakes -sessions -salmon -resolved -remotely -protocol -nickel -nana -garlic -foreman -decency -cord -beds -beam -areas -altogether -uniforms -tremendous -summit -squash -restaurants -rank -profession -popping -peanuts -outa -observe -myrtle -lung -largest -hangs -feelin -experts -enforcement -encouraged -economy -dudes -donation -disguise -curb -continued -competitive -businessman -bites -balloons -antique -advertising -ads -toothbrush -retreat -represents -realistic -profits -predict -panties -lust -lid -landlord -hourglass -hesitate -focusing -equally -consolation -champ -babbling -aged -tipped -stranded -smartest -rhythm -replacement -repeating -puke -psst -paycheck -overreacted -mechanic -macho -ling -leadership -juvenile -images -grocery -freshen -disposal -cuffs -consent -cartoon -caffeine -broom -biology -arguments -agrees -vanished -unfinished -tobacco -tin -tasty -syndrome -stack -sells -ripping -pinch -missiles -isolated -flattering -expenses -dinners -cos -colleague -ciao -buh -attorneys -woulda -whereabouts -wars -waitin -visits -truce -tripped -tee -tasted -steer -ruling -poisoning -pirate -nursing -manipulative -immature -husbands -heel -granddad -delivering -deaths -condoms -butts -automatically -anchor -addict -trashed -tournament -throne -slick -sausage -raining -prices -pasta -needles -leaning -leaders -judges -ideal -detector -coolest -casting -bean -battles -batch -approximately -appointments -almighty -achieve -vegetables -trapper -swinging -sum -spark -ruled -revolution -principles -perfection -pains -momma -mole -meow -jelly -interviews -initiative -hairs -getaway -employment -den -cracking -counted -compliments -behold -verge -tougher -timer -tapped -taped -surf -superman -stakes -specialty -snooping -shoots -semi -rendezvous -pentagon -passenger -leverage -jeopardize -janitor -grandparents -forbidden -fink -examination -communist -clueless -cities -cattle -bidding -arriving -adding -ungrateful -unacceptable -tutor -soviet -shorter -shaped -serum -scuse -savings -pub -pajamas -mouths -mojo -modest -methods -lure -jackass -irrational -galaxy -doom -depth -cries -classified -bombs -beautifully -arresting -approaching -vessel -variety -traitor -sympathetic -smug -smash -rental -prostitute -premonitions -physics -monk -mild -jumps -inventory -ing -improved -horny -doe -developing -darlin -committing -banging -asap -amendment -worms -violated -vent -traumatic -traced -tow -sweaty -shaft -recommended -rainbow -overboard -literature -insight -healed -haven -grasp -fluid -experiencing -era -crappy -crab -chunk -awww -applied -witnessed -traveled -stain -shack -reacted -pronounce -presented -poured -pervert -occupied -moms -marriages -kings -jabez -invested -handful -gob -gag -flipped -flick -fireplace -expertise -embarrassment -drum -disappears -concussion -bruises -brakes -twisting -tide -swept -summon -splitting -sneaky -sloppy -settling -scientists -reschedule -regard -purposes -notch -mustard -moose -les -improvement -hooray -grabbing -extend -exquisite -disrespect -complaints -armor -amateur -wheat -voting -sustained -stripper -straw -slapped -shipped -shattered -ruthless -refill -recorded -payroll -numb -mourning -marijuana -manly -iris -involving -hunk -graham -fountain -fellows -entertain -earthquake -drift -dreadful -doorstep -confirmation -chops -appreciates -announced -vague -tires -stressful -stem -stashed -stash -sensed -preoccupied -predictable -noticing -madly -halls -gunshot -embassy -dozens -dork -confuse -cleaners -charade -chalk -cappuccino -breed -bouquet -amulet -addiction -warming -villa -unlock -transition -satisfy -sacrificed -relaxing -lone -input -fudge -elaborate -concerning -completed -channels -category -cal -blocking -blend -blankets -addicted -yuck -voters -professionals -positions -mode -jolly -initial -hunger -hamburger -greeting -greet -gravy -gram -finance -dreamt -dice -declared -collecting -caution -bicycle -backpack -agreeing -writers -whale -tribe -taller -supervisor -starling -sacrifices -radiation -queens -poo -phew -outcome -ounce -monty -missile -meter -likewise -irrelevant -gran -felon -feature -favorites -farther -fade -experiments -erased -easiest -disk -disco -convenience -conceived -compassionate -challenged -cane -backstage -agony -adores -veins -tweek -thieves -surgical -sunrise -strangely -recital -proposing -productive -meaningful -marching -kitten -immunity -hassle -goddamned -frighten -directors -dearly -comments -closure -cease -bomber -ambition -wage -unstable -sweetness -stinky -salvage -richer -refusing -raging -pumping -pressuring -pookie -petition -nations -mortals -lowlife -jus -juicy -intimidated -intentionally -inspire -forgave -fart -devotion -despicable -deciding -dash -comfy -breach -bark -alternate -aaaah -twilight -switching -swallowed -stove -slot -screamed -scars -relevant -pounding -poof -pipes -persons -pawn -losses -legit -invest -generations -farewell -experimental -difficulty -curtains -civilized -championship -caviar -carnival -canyon -boost -blues -bliss -token -tends -temporarily -superstition -supernatural -sunk -stream -stocks -spinner -sadness -reduced -recorder -rang -psyched -presidential -owners -objects -motivated -microwave -lands -hallelujah -gap -fraternity -engines -dutch -dryer -cocoa -chewing -brake -bounty -additional -acceptable -unbelievably -survivor -smiled -smelling -sized -simpler -sentenced -respectable -remarks -registration -premises -passengers -organ -occasional -indication -gutter -grabs -goo -fulfill -flashlight -courses -chains -boxing -blooded -blink -blessings -beware -bands -advised -von -uhhh -turf -swings -software -slips -shovel -shocking -resistance -puff -privately -mirrors -lyrics -locking -karma -instrument -historical -heartless -fras -echo -decades -comparison -childish -cardiac -brace -blunt -admission -vanilla -utterly -ticked -tequila -suspension -stunned -sadly -resolution -reserved -purely -opponent -noted -mankind -lowest -kiddin -jerks -hitch -flirt -fare -extension -establishment -equals -dismiss -delayed -decade -christening -casket -broker -breakup -biting -antibiotics -accusation -abducted -witchcraft -traded -titan -thread -spelling -smelly -sharks -runnin -remaining -punching -protein -printed -paramedics -newest -murdering -masks -marathon -laptop -intact -ins -initials -heights -grampa -diaper -democracy -deceased -choking -charms -careless -bushes -buns -bummed -accounting -travels -shred -saves -saddle -rethink -regards -references -razor -precinct -pistol -persuade -patterns -meds -manipulating -llanfair -leash -housing -hearted -guarantees -fucks -folk -flown -feast -extent -educated -disgrace -determination -deposition -coverage -corridor -burial -bronze -bookstore -boil -abilities -werewolf -vitals -veil -trespassing -teaches -sidewalk -sensible -punishing -overtime -optimistic -occasions -obsessing -oak -notify -mornin -jeopardy -injection -hilarious -distinct -directed -desires -dee -dame -curve -confide -cone -challenging -cautious -alter -yada -wilderness -vindictive -vial -venture -tomb -teeny -subjects -stroll -sittin -scrub -rebuild -posters -parallel -ordeal -orbit -nuns -northern -intimacy -inheritance -feather -farmer -fails -exploded -donate -distracting -digger -despair -democratic -defended -crackers -commercials -ammunition -wildwind -virtue -thoroughly -tails -spicy -sketches -sights -sheer -shaving -seize -scarecrow -refreshing -prosecute -possess -platter -napkin -misplaced -merchandise -membership -loony -jinx -herr -heroic -fag -facial -efficient -corps -clan -bummer -boundaries -attract -arrow -ambitious -abbey -waits -virtually -syrup -solitary -shuttle -resignation -resemblance -reacting -pursuing -premature -pod -mortgage -journalist -honors -gravity -genes -flashes -erm -contribution -cheque -charts -cargo -awright -acquainted -wrapping -vest -untie -salute -ruins -resign -realised -priceless -pike -partying -myth -moonlight -lightly -lifting -keen -insisting -glowing -generator -flowing -explosives -employer -cutie -confronted -clause -cinnamon -buts -breakthrough -blouse -ballistic -assassin -antidote -analyze -allowance -adjourned -vet -unto -understatement -tucked -touchy -toll -subconscious -sparky -sequence -screws -sarge -roommates -reaches -programs -pitcher -ping -offend -nerd -knives -kin -jasmine -irresistible -inherited -incapable -hostility -goddammit -fuse -funky -frat -equation -digital -curfew -craft -chow -centered -blackmailed -allows -alleged -wealth -watcher -walkin -turtle -transmission -text -starve -sleigh -sarcastic -recess -rebound -rebel -procedures -pirates -pinned -parlor -outfits -livin -issued -institute -industrial -hoops -heartache -haired -fundraiser -dynamite -doorman -documentary -discreet -d -detect -cracks -cracker -considerate -climbed -chilly -catering -author -apophis -vacuum -urine -tunnels -tanks -strung -stitches -sordid -sark -referred -protector -portion -phoned -pets -paths -moss -mat -lengths -kindergarten -hostess -flaw -flavor -diving -discharge -consumed -confidentiality -cannon -bourbon -blizzard -automatic -amongst -yankees -woody -urban -tactics -straightened -spooky -specials -spaghetti -soil -prettier -powerless -por -poems -playin -playground -paranoia -mutant -mainly -lions -knox -jacqueline -instantly -hopeful -havoc -francis -exaggerating -evaluation -engage -eavesdropping -doughnuts -diversion -delight -deepest -dang -cutest -condom -companion -comb -bela -behaving -avoided -aspen -anyplace -agh -accessory -zap -workout -whereas -translate -titanic -stuffing -stoned -speeding -slime -royalty -polls -plaza -personalities -payments -musician -maze -marital -magician -lurking -lottery -leonardo -journalism -interior -imaginary -hog -hatch -guinea -greetings -fairwinds -ethical -equipped -environmental -elegant -elbow -customs -cuban -credibility -credentials -consistent -collapse -cloth -claws -cinderella -chopped -challenges -bridal -boards -bedside -babysitting -authorized -assumption -ant -alvarez -youngest -witty -vast -unforgivable -underworld -tempt -tabs -succeeded -splash -sophomore -shade -selfless -secrecy -santiago -runway -restless -programming -professionally -okey -nolan -movin -metaphor -messes -meltdown -lecter -jeanne -incoming -hence -glenn -gasoline -gained -funding -episodes -diefenbaker -curl -contain -comedian -collected -coconut -cam -buckle -assembly -ancestors -admired -adjustment -acceptance -weekly -warmth -venice -umbrella -tropical -thumbs -throats -slippery -shitty -seduced -reform -ranger -queer -poll -parenting -onion -noses -mobile -luckiest -hartford -graveyard -gifted -francine -footsteps -dimeras -dale -cynical -corleone -cement -bulls -bloom -assassination -wedded -watson -voyage -volunteers -verbal -unpredictable -tuned -triumph -trevor -stoop -stamps -slides -sinking -rio -rigged -regulations -region -promoted -plumbing -pimp -nell -masters -lingerie -layer -jules -hankey -greed -fluffy -flood -everwood -essential -elope -dresser -departure -dat -dances -custom -creation -coup -chauffeur -bulletin -bugged -brian -bouncing -bimbo -website -veal -tubes -temptation -supported -strangest -slammed -selection -sarcasm -sanity -sandra -rib -primitive -platform -pending -partial -packages -orderly -obsessive -newbie -nevertheless -murderers -motto -meteor -inconvenience -hottie -glimpse -froze -fiber -faggot -execute -etc -ensure -drivers -dispute -damages -crop -courageous -consulate -closes -bosses -bees -amends -wuss -wacky -unemployed -traces -testifying -tendency -syringe -symphony -stew -startled -sorrow -sleazy -shaky -screams -runner -rsquo -riddle -remark -rangers -poop -poke -pickup -nutty -mentioning -mend -menace -inspiring -impulsive -housekeeper -harvest -formed -foam -fingernails -economic -divide -conditioning -chronic -bass -baking -whine -utter -thug -submit -strap -starved -sniffing -sedative -reversed -rated -publishing -programmed -picket -paged -online -nowadays -mines -jumbo -joni -invasion -hound -homosexual -homo -hips -gilbert -forgets -flipping -flea -flatter -enters -dwell -dumpster -ducks -devlin -dent -consultant -clayton -choo -bikini -beale -banking -assignments -apartments -ants +absentee +absently +absinthe +absolute +absolve +abstain +abstract +absurd +accent +acclaim +acclimate +accompany +account +accuracy +accurate +accustom +acetone +achiness +aching +acid +acorn +acquaint +acquire +acre +acrobat +acronym +acting +action +activate +activator +active +activism +activist +activity +actress +acts +acutely +acuteness +aeration +aerobics +aerosol +aerospace +afar +affair +affected affecting -advisor -vile -unreasonable -tossing -thanked -stereo -steals -souvenir -screening -scratched -rep -psychopath -proportion -peyton -outs -operative -obstruction -obey -neutral -maxwell -lump -lockdown -insists -harass -gloat -flights -filth -extended -electronic -edgy -donkey -diseases -didn -curtis -coroner -confessing -cologne -cedar -bruise -betraying -bailing -attempting -appealing -adebisi -wrath -wandered -waist -vain -traps -transportation -trainer -sushi -stepfather -rye -publicly -presidents -poking -obligated -monroe -medina -marshal -lemonade -instructed -hooks -heavenly -hash -halt -grim -engineer -employed -doggie -diplomatic -dilemma -crazed -contagious -coaster -cheering -carved -carpenter -butch -bundle -bubbles -blanks -approached -appearances -wrench -vomit -thingy -stadium -speeches -smashing -savior -rogue -robbing -reflect -raft -qualify -pumped -pillows -piggy -peep -pageant -packs -neo -neglected -montana -marcie -madonna -loneliness -liberal -jaye -intrude -indicates -helluva -hawkeye -gregory -gardener -freely -forresters -fatass -err -eleanor -drooling -continuing -cassandra -betcha -apollo -addressed -acquired -vase -tiffany -supermarket -squat -spitting -spice -spaces -slaves -showers -sanchez -rhyme -relieve -receipts -radical -racket -purchased -preserve -portland -pictured -pause -overdue -officials -nod -motivation -morgendorffer -lacking -kidnapper -introduction -insect -hunters -horns -feminine -eyeballs -dumps -disc -disappointing -difficulties -crock -convertible -context -claw -clamp -canned -cambias -bishop -bathtub -avanya -artery -andre -weep -warmer -vendetta -tenth -suspense -summoned -spiders -sings -reiber -reader -raving -pushy -produced -poverty -postponed -poppy -ohhhh -noooo -mold -mice -laughter -johnnie -incompetent -hugging -horizon -grove -groceries -frequency -fastest -drip -dinosaur -differ -delta -copper -communicating -clare -chi -carrier -brody -beliefs -bats -bases -auntie -adios -wraps -wiser -willingly -weirdest -waltz -voila -timmih -thinner -swelling -swat -steroids -slate -sentinel -sensitivity -scrape -rookie -rehearse -quarterback -prophecy -organic -mercedes -matched -ledge -justified -insults -increased -immortal -heavily -hateful -handles -francie -feared -einstein -doorway -decorations -colour -chatting -buyer -buckaroo -bedrooms -batting -askin -ammo -admiral -wrestle -wolves -velvet -tutoring -subpoena -stein -span -scratching -requests -privileges -pager -mart -manor -madman -knicks -kel -intriguing -idiotic -hotels -grape -granger -goofy -flexible -enlighten -dum -donuts -demonstrate -dairy -corrupt -combined -brunch -bridesmaid -barking -architect -applause +affection +affidavit +affiliate +affirm +affix +afflicted +affluent +afford +affront +aflame +afloat +aflutter +afoot +afraid +afterglow +afterlife +aftermath +aftermost +afternoon +aged +ageless +agency +agenda +agent +aggregate +aghast +agile +agility +aging +agnostic +agonize +agonizing +agony +agreeable +agreeably +agreed +agreeing +agreement +aground +ahead +ahoy +aide +aids +aim +ajar +alabaster +alarm +albatross +album +alfalfa +algebra +algorithm +alias +alibi +alienable +alienate +aliens +alike +alive +alkaline +alkalize +almanac +almighty +almost +aloe +aloft +aloha +alone alongside -ale -acquaintance -yuh -wretched -tango -superficial -sufficient -sued -soak -smoothly -sensing -restraint -quo -posing -pleading -payoff -participate -panda -organize -morals -loans -loaf -lists -laboratory -jumpy -intervention -ignorant -herbal -hangin -germs -generosity -freed -flashing -doughnut -convent -clumsy -chocolates -captive -behaved -babes -apologise -angelus -vanity -trials -stumbled -skate -shampoo -republicans -represented -recognition -preview -poisonous -perjury -parental -onboard -mugged -minding -maestro -linen -learns -knots -jimbo -interviewing -inmates -ingredients -humour -gypsy -grind -greasy -goons -frost -estimate -elementary -drastic -dolly -database -crow -coop -comparing -cocky -clearer -cartoons -bruised -brag -bind -axe -asset -apparent -worthwhile -whoop -warner -volcano -vanquishing -towns -tabloids -survivors -sprung -spotlight -smokes -shops -sentencing -sentences -rivers -revealing -reduce -ram -racist -provoke -preacher -pining -peak -password -overly -oui -ops -mop -mayo -locket -leland -jab -imply -impatient -hovering -hotter -holland -gemini -gaines -fest -endure -dots -doren -dim -diagnosed -debts -cultures -crawled -contained -condemned -cody -chained -brit -breaths -booty -arctic -ambrosia -adds -weirdo -warmed -wand -vienna -utah -troubling -stripped -strapped -spies -soaked -skipping -scrambled -rattle -profound -perez -peoples -musta -moses -mona -mocking -mnh -misunderstand -merit -mayday -loading -linked -limousine -kacl -jody -investors -interviewed -hustle -forensic -foods -espresso -enthusiastic -duct -drawers -devastating -democrats -cosmo -conquer -concentration -comeback -clarify -chores -cheerleaders -cheaper -charter -chantal -callin -butcher -bricks -bozo -blushing -bert -barging -asia -abused -yoga -wrecking -wits -wentworth -waffles -virginity -vibes -uninvited -unfaithful -underwater -tribute -teller -strangled -sissy -scheming -ropes -responded -residents -rescuing -reel -redhead -rave -priests -postcard -peterman -overseas -orientation -onions -ongoing -newly -morphine -lotion -limitations -lilly -lesser -lent -lectures -lads -kidneys -judgement -jog -jingle -jets -itch -intellectual -installed -infant -indefinitely -hazard -grenade -glamorous -genetically -fireman -faculty -engineering -doh -discretion -delusions -declaration -crate -competent -commonwealth -catalog -breaker -blondie -bakery -attempts -asylum -argh -applying -ahhhh -wedge -warriors -wager -unfit -tuxedo -tripping -treatments -torment -superhero -stirring -spinal -sorority -sneakers -server -seminar -scenery -republic -repairs -rabble -pneumonia -perks -peaches -owl -override -ooooh -moo -mija -manslaughter -mailed -lime -lettuce -kinky -intimidate -instructor -guarded -grieve -grad -gorilla -globe -frustration -extensive -exploring -exercises -downs -doorbell -devices -deb -dam -cultural -credits -commerce -chemicals -cafรฉ -authentic -arraignment -annulled -altered -allergies -wanta -verify -vegetarian -tunes -tourist -tighter -telegram -suitable -stalk -springs -specimen -spared -solving -shoo -satisfying -requesting -publisher -pharmacy - -pens -overprotective -obstacles -notified -negro -nasedo -judged -identification -grandchild -genuinely -founded -flushed -fluids -floss -escaping -dove -ditched -decorated -crunch -criticism -cramp -corny -contribute -connecting -bunk -bombing -bitten -billions -bankrupt -yikes -wrists -winners -ultrasound -ultimatum -thirst -suckers -spelled -sniff -shakes -scope -salsa -retrieve -releasing -reassuring -pumps -properties -predicted -pigeon -neurotic -negotiating -multi -monitors -millionaire -microphone -mechanical -limp -incriminating -hiking -hatchet -gracias -fills -feeds -doubting -dedication -decaf -competing -cellular -carbon -butterfly -bumper -biopsy -whiz -voluntarily -visible -ventilator -unpack -unload -universal -tomatoes -toad -targets -taco -suggests -strawberry -spooked -snitch -showtime -sap -reassure -providing -prey -persuasive -pancake -mystical -mysteries -mixing -mayhem -matrimony -marines -mails -magnet -lighthouse -liability -jock -headline -groovy -gangster -factors -explosive -explanations -dispatch -detailed -curly -cupid -condolences -comrade -bulb -bragging -awaits -assaulted +aloof +alphabet +alright +although +altitude +alto +aluminum +alumni +always +amaretto +amaze +amazingly +amber +ambiance +ambiguity +ambiguous +ambition +ambitious +ambulance ambush -aircraft -adolescent -adjusted -abort -yank -whit -verse -vaguely -undermine -tying -trim -swamped -sunlight -stitch -stabbing -sphere -slippers -slash -sincerely -sigh -setback -secondly -rotting -rev -retail -prospect -proceedings -preparation -precaution -pox -pearls -pcpd -parks -nonetheless -melting -materials -marler -mar -liaison -lair -hots -hooking -headlines -haha -hag -grapes -genie -fury -felicity -fangs -expelled -encouragement -earring -dreidel -draws -dory -donut -dis -dictate -dependent -decorating -cunt -cope -coordinates -cola -cocktails -cocksucker -bumps -blueberry -blackout -believable -backfired -backfire -apron -anticipated +amendable +amendment +amends +amenity +amiable +amicably +amid amigo -adjusting -activated -vous -vouch -voodoo -vitamins -vista -vintage -urn -uncertain -ummm -tourists -tattoos -surrounding -stern -sponsor -slimy -singles -sibling -shhhh -restored -representative -renting -reign -publish -planets -pickle -peculiar -parasite -noo -marries -mailbox -magically -lovebirds -listeners -knocks -intel -informant -hicks -grain -fearless -exits -elf -drazen -distractions -disconnected -dinosaurs -designing -dashwood -crooked -crook -conveniently -contents -colon -barber -argued -ziggy -wink -warped -underestimated -testified -tacky -substantial -steering -staged -stability -shoving -shaved -seizure -reset -repeatedly -radius -pushes -pitching -pairs -painter -opener -notebook -mornings -moody -mash -investigations -invent -indulge -horribly -hallucinating -festive -feathers -eyebrows -expand -enjoys -dictionary -dialogue -desperation -dealers -darkest -daph -critic -cowboys -consulting -canal -boragora -belts -bananas -bagel -authorization -auditions -associated -ape -agitated -adventures -withdraw -wishful -wimp -violin -vehicles -vanish -unbearable -tonic -tackle -suffice -suction -sporting -slaying -safest -rocking -relive -rates -puttin -puppies -prettiest -polo -oval -oatmeal -noisy -newlyweds -nauseous -moi -misguided -mildly -midst -maps -liable -judgmental -introducing -indy -individuals -hunted -hen -givin -frequent -fisherman -fascinated -elephants -dislike -diploma -deluded -decorate -crummy -contractions -carve -careers -bottled -bonded -birdie -bash -whites -unavailable -twenties -trustworthy -translation -traditions -surviving -surgeons -stupidity -snoop -skies -secured -salvation -remorse -preferably -pies -photography -outsider -operational -nuh -northwest -nausea -napkins -mule -mourn -melted -mechanism -mashed -maiden -mafia -inherit -holdings -hel -greatness -golly -girlie -excused -edges -dumbo -drifting -delirious -damaging -cubicle -crawley -compelled -comm -colleges -chooses -checkup -certified -candidates -buffet -boredom -bandages -bah -automobile -athletic -alarms -absorbed -absent -yessir -windshield -whaddya -vitamin -viper -transparent -surprisingly -sunglasses -starring -spears -slit -sided -serenity -schemes -roar -relatively -quarry -prosecutor -prognosis -probe -potentially -poodle -pitiful -persistent -perception -percentage -peas -oww -nosy -neighbourhood -nagging -morons -molecular -meters -masterpiece -martinis -limbo -liars -karate -irritating -inclined -hump -hoynes -holler -hazel -haw -gauge -functions -fiasco -fallout -educational -eatin -dumbass -donated -destination -dense -crimson -continent -concentrating -commanding -colorful -clam -cider -brochure -behaviour -barto -bargaining -awe -artistic +amino +amiss +ammonia +ammonium +amnesty +amniotic +among +amount +amperage +ample +amplifier +amplify +amply +amuck +amulet +amusable +amused +amusement +amuser +amusing +anaconda +anaerobic +anagram +anatomist +anatomy +anchor +anchovy +ancient +android +anemia +anemic +aneurism +anew +angelfish +angelic +anger +angled +angler +angles +angling +angrily +angriness +anguished +angular +animal +animate +animating +animation +animator +anime +animosity +ankle +annex +annotate +announcer +annoying +annually +annuity +anointer +another +answering +antacid +antarctic +anteater +antelope +antennae +anthem +anthill +anthology +antibody +antics +antidote +antihero +antiquely +antiques +antiquity +antirust +antitoxic +antitrust +antiviral +antivirus +antler +antonym +antsy +anvil +anybody +anyhow +anymore +anyone +anyplace +anything +anytime +anyway +anywhere +aorta +apache +apostle +appealing +appear +appease +appeasing +appendage +appendix +appetite +appetizer +applaud +applause +apple +appliance +applicant +applied +apply +appointee +appraisal +appraiser +apprehend +approach +approval +approve +apricot +april +apron +aptitude +aptly +aqua +aqueduct +arbitrary +arbitrate +ardently +area arena -wiggle -welcoming -weighing -villain -vein -vanquished -striking -stains -sooo -snacks -smear -sire -secondary -roughly -rituals -resentment -psychologist -preferred -pint -pension -penguin -passive -panther -overhear -origin -orchestra -negotiations -mounted -morality -leopard -labs -kisser -jackpot -icy -hoot -hippie -handshake -grilled -functioning -formality -elevators -drums -depths -confirms -civilians -bypass -briefly -breeding -boxer -boathouse -binding +arguable +arguably +argue +arise +armadillo +armband +armchair +armed +armful +armhole +arming +armless +armoire +armored +armory +armrest +army +aroma +arose +around +arousal +arrange +array +arrest +arrival +arrive +arrogance +arrogant +arson +art +ascend +ascension +ascent +ascertain +ashamed +ashen +ashes +ashy +aside +askew +asleep +asparagus +aspect +aspirate +aspire +aspirin +astonish +astound +astride +astrology +astronaut +astronomy +astute +atlantic +atlas +atom +atonable +atop +atrium +atrocious +atrophy +attach +attain +attempt +attendant +attendee +attention +attentive +attest +attic +attire +attitude +attractor +attribute +atypical +auction +audacious +audacity +audible +audibly +audience audio -acres -accidental -wacko -ulterior -transferring -tis -thugs -thighs -tangled -stirred -sought -softball -snag -smallest -sling -sleaze -shells -seeds -rumour -ripe -remarried -reluctant -regularly -puddle -promote -precise -popularity -pins -perceptive -oral -miraculous -memorable -maternal -lookout -longing -lockup -locals -lizard -librarian -knights -junkie -inspection -impressions -immoral -hypothetically -guarding -gourmet -fighters -fees -features -faxed -extortion -expressed -essentially -downright -digest -der -crosses -cranberry -covert -costa -chorus -casualties -bygones -buzzing -burying -bugger -bikes -attended -wells -weary -visa -viewing -viewers -uptown -transmitter -trains -tickle -tart -taping -takeout -sweeping -stepmother -stating -stale -seรฑor -settles -seating -seaborn -resigned -rating -pros -porno -plumber -pissing -pilots -pepperoni -ownership -occurs -newborn -nada -merger -mandatory -ludicrous -injected -heating -geeks -forged -faults -expressing -drue -dire -dief -deceiving -centre -celebrities +audition +augmented +august +authentic +author +autism +autistic +autograph +automaker +automated +automatic +autopilot +available +avalanche +avatar +avenge +avenging +avenue +average +aversion +avert +aviation +aviator +avid +avoid +await +awaken +award +aware +awhile +awkward +awning +awoke +awry +axis +babble +babbling +babied +baboon +backache +backboard +backboned +backdrop +backed +backer +backfield +backfire +backhand +backing +backlands +backlash +backless +backlight +backlit +backlog +backpack +backpedal +backrest +backroom +backshift +backside +backslid +backspace +backspin +backstab +backstage +backtalk +backtrack +backup +backward +backwash +backwater +backyard +bacon +bacteria +bacterium +badass +badge +badland +badly +badness +baffle +baffling +bagel +bagful +baggage +bagged +baggie +bagginess +bagging +baggy +bagpipe +baguette +baked +bakery +bakeshop +baking +balance +balancing +balcony +balmy +balsamic +bamboo +banana +banish +banister +banjo +bankable +bankbook +banked +banker +banking +banknote +bankroll +banner +bannister +banshee +banter +barbecue +barbed +barbell +barber +barcode +barge +bargraph +barista +baritone +barley +barmaid +barman +barn +barometer +barrack +barracuda +barrel +barrette +barricade +barrier +barstool +bartender +barterer +bash +basically +basics +basil +basin +basis +basket +batboy +batch +bath +baton +bats +battalion +battered +battering +battery +batting +battle +bauble +bazooka +blabber +bladder +blade +blah +blame +blaming +blanching +blandness +blank +blaspheme +blasphemy +blast +blatancy +blatantly +blazer +blazing +bleach +bleak +bleep +blemish +blend +bless +blighted +blimp +bling +blinked +blinker +blinking +blinks +blip +blissful +blitz +blizzard +bloated +bloating +blob +blog +bloomers +blooming +blooper +blot +blouse +blubber +bluff +bluish +blunderer +blunt +blurb +blurred +blurry +blurt +blush +blustery +boaster +boastful +boasting +boat +bobbed +bobbing +bobble +bobcat +bobsled +bobtail +bodacious +body +bogged +boggle +bogus +boil +bok +bolster +bolt +bonanza +bonded +bonding +bondless +boned +bonehead +boneless +bonelike +boney +bonfire +bonnet +bonsai +bonus +bony +boogeyman +boogieman +book +boondocks +booted +booth +bootie +booting +bootlace +bootleg +boots +boozy +borax +boring +borough +borrower +borrowing +boss +botanical +botanist +botany +botch +both +bottle +bottling +bottom +bounce +bouncing +bouncy +bounding +boundless +bountiful +bovine +boxcar +boxer +boxing +boxlike +boxy +breach +breath +breeches +breeching +breeder +breeding +breeze +breezy +brethren +brewery +brewing +briar +bribe +brick +bride +bridged +brigade +bright +brilliant +brim +bring +brink +brisket +briskly +briskness +bristle +brittle +broadband +broadcast +broaden +broadly +broadness +broadside +broadways +broiler +broiling +broken +broker +bronchial +bronco +bronze +bronzing +brook +broom +brought +browbeat +brownnose +browse +browsing +bruising +brunch +brunette +brunt +brush +brussels +brute +brutishly +bubble +bubbling +bubbly +buccaneer +bucked +bucket +buckle +buckshot +buckskin +bucktooth +buckwheat +buddhism +buddhist +budding +buddy +budget +buffalo +buffed +buffer +buffing +buffoon +buggy +bulb +bulge +bulginess +bulgur +bulk +bulldog +bulldozer +bullfight +bullfrog +bullhorn +bullion +bullish +bullpen +bullring +bullseye +bullwhip +bully +bunch +bundle +bungee +bunion +bunkbed +bunkhouse +bunkmate +bunny +bunt +busboy +bush +busily +busload +bust +busybody +buzz +cabana +cabbage +cabbie +cabdriver +cable +caboose +cache +cackle +cacti +cactus +caddie +caddy +cadet +cadillac +cadmium +cage +cahoots +cake +calamari +calamity +calcium +calculate +calculus +caliber +calibrate +calm +caloric +calorie +calzone +camcorder +cameo +camera +camisole +camper +campfire +camping +campsite +campus +canal +canary +cancel +candied +candle +candy +cane +canine +canister +cannabis +canned +canning +cannon +cannot +canola +canon +canopener +canopy +canteen +canyon +capable +capably +capacity +cape +capillary +capital +capitol +capped +capricorn +capsize +capsule +caption +captivate +captive +captivity +capture +caramel +carat +caravan +carbon +cardboard +carded +cardiac +cardigan +cardinal +cardstock +carefully +caregiver +careless +caress +caretaker +cargo +caring +carless +carload +carmaker +carnage +carnation +carnival +carnivore +carol +carpenter +carpentry +carpool +carport +carried +carrot +carrousel +carry +cartel +cartload +carton +cartoon +cartridge +cartwheel +carve +carving +carwash +cascade +case +cash +casing +casino +casket +cassette +casually +casualty +catacomb +catalog +catalyst +catalyze +catapult +cataract +catatonic +catcall +catchable +catcher +catching +catchy caterer -carrots -calmed -businesses -budge -bridges -applications -ankles -vending -typing -tribbiani -swift -squared -speculation -snowing -shades -sexist -scattered -sanctuary -saints -rewrite -regretted -regain -raises -processing -picky -orphan -nipples -nam +catering +catfight +catfish +cathedral +cathouse +catlike +catnap +catnip +catsup +cattail +cattishly +cattle +catty +catwalk +caucasian +caucus +causal +causation +cause +causing +cauterize +caution +cautious +cavalier +cavalry +caviar +cavity +cedar +celery +celestial +celibacy +celibate +celtic +cement +census +ceramics +ceremony +certainly +certainty +certified +certify +cesarean +cesspool +chafe +chaffing +chain +chair +chalice +challenge +chamber +chamomile +champion +chance +change +channel +chant +chaos +chaperone +chaplain +chapped +chaps +chapter +character +charbroil +charcoal +charger +charging +chariot +charity +charm +charred +charter +charting +chase +chasing +chaste +chastise +chastity +chatroom +chatter +chatting +chatty +cheating +cheddar +cheek +cheer +cheese +cheesy +chef +chemicals +chemist +chemo +cherisher +cherub +chess +chest +chevron +chevy +chewable +chewer +chewing +chewy +chief +chihuahua +childcare +childhood +childish +childless +childlike +chili +chill +chimp +chip +chirping +chirpy +chitchat +chivalry +chive +chloride +chlorine +choice +chokehold +choking +chomp +chooser +choosing +choosy +chop +chosen +chowder +chowtime +chrome +chubby +chuck +chug +chummy +chump +chunk +churn +chute +cider +cilantro +cinch +cinema +cinnamon +circle +circling +circular +circulate +circus +citable +citadel +citation +citizen +citric +citrus +city +civic +civil +clad +claim +clambake +clammy +clamor +clamp +clamshell +clang +clanking +clapped +clapper +clapping +clarify +clarinet +clarity +clash +clasp +class +clatter +clause +clavicle +claw +clay +clean +clear +cleat +cleaver +cleft +clench +clergyman +clerical +clerk +clever +clicker +client +climate +climatic +cling +clinic +clinking +clip +clique +cloak +clobber +clock +clone +cloning +closable +closure +clothes +clothing +cloud +clover +clubbed +clubbing +clubhouse +clump +clumsily +clumsy +clunky +clustered +clutch +clutter +coach +coagulant +coastal +coaster +coasting +coastland +coastline +coat +coauthor +cobalt +cobbler +cobweb +cocoa +coconut +cod +coeditor +coerce +coexist +coffee +cofounder +cognition +cognitive +cogwheel +coherence +coherent +cohesive +coil +coke +cola +cold +coleslaw +coliseum +collage +collapse +collar +collected +collector +collide +collie +collision +colonial +colonist +colonize +colony +colossal +colt +coma +come +comfort +comfy +comic +coming +comma +commence +commend +comment +commerce +commode +commodity +commodore +common +commotion +commute +commuting +compacted +compacter +compactly +compactor +companion +company +compare +compel +compile +comply +component +composed +composer +composite +compost +composure +compound +compress +comprised +computer +computing +comrade +concave +conceal +conceded +concept +concerned +concert +conch +concierge +concise +conclude +concrete +concur +condense +condiment +condition +condone +conducive +conductor +conduit +cone +confess +confetti +confidant +confident +confider +confiding +configure +confined +confining +confirm +conflict +conform +confound +confront +confused +confusing +confusion +congenial +congested +congrats +congress +conical +conjoined +conjure +conjuror +connected +connector +consensus +consent +console +consoling +consonant +constable +constant +constrain +constrict +construct +consult +consumer +consuming +contact +container +contempt +contend +contented +contently +contents +contest +context +contort +contour +contrite +control +contusion +convene +convent +copartner +cope +copied +copier +copilot +coping +copious +copper +copy +coral +cork +cornball +cornbread +corncob +cornea +corned +corner +cornfield +cornflake +cornhusk +cornmeal +cornstalk +corny +coronary +coroner +corporal +corporate +corral +correct +corridor +corrode +corroding +corrosive +corsage +corset +cortex +cosigner +cosmetics +cosmic +cosmos +cosponsor +cost +cottage +cotton +couch +cough +could +countable +countdown +counting +countless +country +county +courier +covenant +cover +coveted +coveting +coyness +cozily +coziness +cozy +crabbing +crabgrass +crablike +crabmeat +cradle +cradling +crafter +craftily +craftsman +craftwork +crafty +cramp +cranberry +crane +cranial +cranium +crank +crate +crave +craving +crawfish +crawlers +crawling +crayfish +crayon +crazed +crazily +craziness +crazy +creamed +creamer +creamlike +crease +creasing +creatable +create +creation +creative +creature +credible +credibly +credit +creed +creme +creole +crepe +crept +crescent +crested +cresting +crestless +crevice +crewless +crewman +crewmate +crib +cricket +cried +crier +crimp +crimson +cringe +cringing +crinkle +crinkly +crisped +crisping +crisply +crispness +crispy +criteria +critter +croak +crock +crook +croon +crop +cross +crouch +crouton +crowbar +crowd +crown +crucial +crudely +crudeness +cruelly +cruelness +cruelty +crumb +crummiest +crummy +crumpet +crumpled +cruncher +crunching +crunchy +crusader +crushable +crushed +crusher +crushing +crust +crux +crying +cryptic +crystal +cubbyhole +cube +cubical +cubicle +cucumber +cuddle +cuddly +cufflink +culinary +culminate +culpable +culprit +cultivate +cultural +culture +cupbearer +cupcake +cupid +cupped +cupping +curable +curator +curdle +cure +curfew +curing +curled +curler +curliness +curling +curly +curry +curse +cursive +cursor +curtain +curtly +curtsy +curvature +curve +curvy +cushy +cusp +cussed +custard +custodian +custody +customary +customer +customize +customs +cut +cycle +cyclic +cycling +cyclist +cylinder +cymbal +cytoplasm +cytoplast +dab +dad +daffodil +dagger +daily +daintily +dainty +dairy +daisy +dallying +dance +dancing +dandelion +dander +dandruff +dandy +danger +dangle +dangling +daredevil +dares +daringly +darkened +darkening +darkish +darkness +darkroom +darling +darn +dart +darwinism +dash +dastardly +data +datebook +dating +daughter +daunting +dawdler +dawn +daybed +daybreak +daycare +daydream +daylight +daylong +dayroom +daytime +dazzler +dazzling +deacon +deafening +deafness +dealer +dealing +dealmaker +dealt +dean +debatable +debate +debating +debit +debrief +debtless +debtor +debug +debunk +decade +decaf +decal +decathlon +decay +deceased +deceit +deceiver +deceiving +december +decency +decent +deception +deceptive +decibel +decidable +decimal +decimeter +decipher +deck +declared +decline +decode +decompose +decorated +decorator +decoy +decrease +decree +dedicate +dedicator +deduce +deduct +deed +deem +deepen +deeply +deepness +deface +defacing +defame +default +defeat +defection +defective +defendant +defender +defense +defensive +deferral +deferred +defiance +defiant +defile +defiling +define +definite +deflate +deflation +deflator +deflected +deflector +defog +deforest +defraud +defrost +deftly +defuse +defy +degraded +degrading +degrease +degree +dehydrate +deity +dejected +delay +delegate +delegator +delete +deletion +delicacy +delicate +delicious +delighted +delirious +delirium +deliverer +delivery +delouse +delta +deluge +delusion +deluxe +demanding +demeaning +demeanor +demise +democracy +democrat +demote +demotion +demystify +denatured +deniable +denial +denim +denote +dense +density +dental +dentist +denture +deny +deodorant +deodorize +departed +departure +depict +deplete +depletion +deplored +deploy +deport +depose +depraved +depravity +deprecate +depress +deprive +depth +deputize +deputy +derail +deranged +derby +derived +desecrate +deserve +deserving +designate +designed +designer +designing +deskbound +desktop +deskwork +desolate +despair +despise +despite +destiny +destitute +destruct +detached +detail +detection +detective +detector +detention +detergent +detest +detonate +detonator +detoxify +detract +deuce +devalue +deviancy +deviant +deviate +deviation +deviator +device +devious +devotedly +devotee +devotion +devourer +devouring +devoutly +dexterity +dexterous +diabetes +diabetic +diabolic +diagnoses +diagnosis +diagram +dial +diameter +diaper +diaphragm +diary +dice +dicing +dictate +dictation +dictator +difficult +diffused +diffuser +diffusion +diffusive +dig +dilation +diligence +diligent +dill +dilute +dime +diminish +dimly +dimmed +dimmer +dimness +dimple +diner +dingbat +dinghy +dinginess +dingo +dingy +dining +dinner +diocese +dioxide +diploma +dipped +dipper +dipping +directed +direction +directive +directly +directory +direness +dirtiness +disabled +disagree +disallow +disarm +disarray +disaster +disband +disbelief +disburse +discard +discern +discharge +disclose +discolor +discount +discourse +discover +discuss +disdain +disengage +disfigure +disgrace +dish +disinfect +disjoin +disk +dislike +disliking +dislocate +dislodge +disloyal +dismantle +dismay +dismiss +dismount +disobey +disorder +disown +disparate +disparity +dispatch +dispense +dispersal +dispersed +disperser +displace +display +displease +disposal +dispose +disprove +dispute +disregard +disrupt +dissuade +distance +distant +distaste +distill +distinct +distort +distract +distress +district +distrust +ditch +ditto +ditzy +dividable +divided +dividend +dividers +dividing +divinely +diving +divinity +divisible +divisibly +division +divisive +divorcee +dizziness +dizzy +doable +docile +dock +doctrine +document +dodge +dodgy +doily +doing +dole +dollar +dollhouse +dollop +dolly +dolphin +domain +domelike +domestic +dominion +dominoes +donated +donation +donator +donor +donut +doodle +doorbell +doorframe +doorknob +doorman +doormat +doornail +doorpost +doorstep +doorstop +doorway +doozy +dork +dormitory +dorsal +dosage +dose +dotted +doubling +douche +dove +down +dowry +doze +drab +dragging +dragonfly +dragonish +dragster +drainable +drainage +drained +drainer +drainpipe +dramatic +dramatize +drank +drapery +drastic +draw +dreaded +dreadful +dreadlock +dreamboat +dreamily +dreamland +dreamless +dreamlike +dreamt +dreamy +drearily +dreary +drench +dress +drew +dribble +dried +drier +drift +driller +drilling +drinkable +drinking +dripping +drippy +drivable +driven +driver +driveway +driving +drizzle +drizzly +drone +drool +droop +drop-down +dropbox +dropkick +droplet +dropout +dropper +drove +drown +drowsily +drudge +drum +dry +dubbed +dubiously +duchess +duckbill +ducking +duckling +ducktail +ducky +duct +dude +duffel +dugout +duh +duke +duller +dullness +duly +dumping +dumpling +dumpster +duo +dupe +duplex +duplicate +duplicity +durable +durably +duration +duress +during +dusk +dust +dutiful +duty +duvet +dwarf +dweeb +dwelled +dweller +dwelling +dwindle +dwindling +dynamic +dynamite +dynasty +dyslexia +dyslexic +each +eagle +earache +eardrum +earflap +earful +earlobe +early +earmark +earmuff +earphone +earpiece +earplugs +earring +earshot +earthen +earthlike +earthling +earthly +earthworm +earthy +earwig +easeful +easel +easiest +easily +easiness +easing +eastbound +eastcoast +easter +eastward +eatable +eaten +eatery +eating +eats +ebay +ebony +ebook +ecard +eccentric +echo +eclair +eclipse +ecologist +ecology +economic +economist +economy +ecosphere +ecosystem +edge +edginess +edging +edgy +edition +editor +educated +education +educator +eel +effective +effects +efficient +effort +eggbeater +egging +eggnog +eggplant +eggshell +egomaniac +egotism +egotistic +either +eject +elaborate +elastic +elated +elbow +eldercare +elderly +eldest +electable +election +elective +elephant +elevate +elevating +elevation +elevator +eleven +elf +eligible +eligibly +eliminate +elite +elitism +elixir +elk +ellipse +elliptic +elm +elongated +elope +eloquence +eloquent +elsewhere +elude +elusive +elves +email +embargo +embark +embassy +embattled +embellish +ember +embezzle +emblaze +emblem +embody +embolism +emboss +embroider +emcee +emerald +emergency +emission +emit +emote +emoticon +emotion +empathic +empathy +emperor +emphases +emphasis +emphasize +emphatic +empirical +employed +employee +employer +emporium +empower +emptier +emptiness +empty +emu +enable +enactment +enamel +enchanted +enchilada +encircle +enclose +enclosure +encode +encore +encounter +encourage +encroach +encrust +encrypt +endanger +endeared +endearing +ended +ending +endless +endnote +endocrine +endorphin +endorse +endowment +endpoint +endurable +endurance +enduring +energetic +energize +energy +enforced +enforcer +engaged +engaging +engine +engorge +engraved +engraver +engraving +engross +engulf +enhance +enigmatic +enjoyable +enjoyably +enjoyer +enjoying +enjoyment +enlarged +enlarging +enlighten +enlisted +enquirer +enrage +enrich +enroll +enslave +ensnare +ensure +entail +entangled +entering +entertain +enticing +entire +entitle +entity +entomb +entourage +entrap +entree +entrench +entrust +entryway +entwine +enunciate +envelope +enviable +enviably +envious +envision +envoy +envy +enzyme +epic +epidemic +epidermal +epidermis +epidural +epilepsy +epileptic +epilogue +epiphany +episode +equal +equate +equation +equator +equinox +equipment +equity +equivocal +eradicate +erasable +erased +eraser +erasure +ergonomic +errand +errant +erratic +error +erupt +escalate +escalator +escapable +escapade +escapist +escargot +eskimo +esophagus +espionage +espresso +esquire +essay +essence +essential +establish +estate +esteemed +estimate +estimator +estranged +estrogen +etching +eternal +eternity +ethanol +ether +ethically +ethics +euphemism +evacuate +evacuee +evade +evaluate +evaluator +evaporate +evasion +evasive +even +everglade +evergreen +everybody +everyday +everyone +evict +evidence +evident +evil +evoke +evolution +evolve +exact +exalted +example +excavate +excavator +exceeding +exception +excess +exchange +excitable +exciting +exclaim +exclude +excluding +exclusion +exclusive +excretion +excretory +excursion +excusable +excusably +excuse +exemplary +exemplify +exemption +exerciser +exert +exes +exfoliate +exhale +exhaust +exhume +exile +existing +exit +exodus +exonerate +exorcism +exorcist +expand +expanse +expansion +expansive +expectant +expedited +expediter +expel +expend +expenses +expensive +expert +expire +expiring +explain +expletive +explicit +explode +exploit +explore +exploring +exponent +exporter +exposable +expose +exposure +express +expulsion +exquisite +extended +extending +extent +extenuate +exterior +external +extinct +extortion +extradite +extras +extrovert +extrude +extruding +exuberant +fable +fabric +fabulous +facebook +facecloth +facedown +faceless +facelift +faceplate +faceted +facial +facility +facing +facsimile +faction +factoid +factor +factsheet +factual +faculty +fade +fading +failing +falcon +fall +false +falsify +fame +familiar +family +famine +famished +fanatic +fancied +fanciness +fancy +fanfare +fang +fanning +fantasize +fantastic +fantasy +fascism +fastball +faster +fasting +fastness +faucet +favorable +favorably +favored +favoring +favorite +fax +feast +federal +fedora +feeble +feed +feel +feisty +feline +felt-tip +feminine +feminism +feminist +feminize +femur +fence +fencing +fender +ferment +fernlike +ferocious +ferocity +ferret +ferris +ferry +fervor +fester +festival +festive +festivity +fetal +fetch +fever +fiber +fiction +fiddle +fiddling +fidelity +fidgeting +fidgety +fifteen +fifth +fiftieth +fifty +figment +figure +figurine +filing +filled +filler +filling +film +filter +filth +filtrate +finale +finalist +finalize +finally +finance +financial +finch +fineness +finer +finicky +finished +finisher +finishing +finite +finless +finlike +fiscally +fit +five +flaccid +flagman +flagpole +flagship +flagstick +flagstone +flail +flakily +flaky +flame +flammable +flanked +flanking +flannels +flap +flaring +flashback +flashbulb +flashcard +flashily +flashing +flashy +flask +flatbed +flatfoot +flatly +flatness +flatten +flattered +flatterer +flattery +flattop +flatware +flatworm +flavored +flavorful +flavoring +flaxseed +fled +fleshed +fleshy +flick +flier +flight +flinch +fling +flint +flip +flirt +float +flock +flogging +flop +floral +florist +floss +flounder +flyable +flyaway +flyer +flying +flyover +flypaper +foam +foe +fog +foil +folic +folk +follicle +follow +fondling +fondly +fondness +fondue +font +food +fool +footage +football +footbath +footboard +footer +footgear +foothill +foothold +footing +footless +footman +footnote +footpad +footpath +footprint +footrest +footsie +footsore +footwear +footwork +fossil +foster +founder +founding +fountain +fox +foyer +fraction +fracture +fragile +fragility +fragment +fragrance +fragrant +frail +frame +framing +frantic +fraternal +frayed +fraying +frays +freckled +freckles +freebase +freebee +freebie +freedom +freefall +freehand +freeing +freeload +freely +freemason +freeness +freestyle +freeware +freeway +freewill +freezable +freezing +freight +french +frenzied +frenzy +frequency +frequent +fresh +fretful +fretted +friction +friday +fridge +fried +friend +frighten +frightful +frigidity +frigidly +frill +fringe +frisbee +frisk +fritter +frivolous +frolic +from +front +frostbite +frosted +frostily +frosting +frostlike +frosty +froth +frown +frozen +fructose +frugality +frugally +fruit +frustrate +frying +gab +gaffe +gag +gainfully +gaining +gains +gala +gallantly +galleria +gallery +galley +gallon +gallows +gallstone +galore +galvanize +gambling +game +gaming +gamma +gander +gangly +gangrene +gangway +gap +garage +garbage +garden +gargle +garland +garlic +garment +garnet +garnish +garter +gas +gatherer +gathering +gating +gauging +gauntlet +gauze +gave +gawk +gazing +gear +gecko +geek +geiger +gem +gender +generic +generous +genetics +genre +gentile +gentleman +gently +gents +geography +geologic +geologist +geology +geometric +geometry +geranium +gerbil +geriatric +germicide +germinate +germless +germproof +gestate +gestation +gesture +getaway +getting +getup +giant +gibberish +giblet +giddily +giddiness +giddy +gift +gigabyte +gigahertz +gigantic +giggle +giggling +giggly +gigolo +gilled +gills +gimmick +girdle +giveaway +given +giver +giving +gizmo +gizzard +glacial +glacier +glade +gladiator +gladly +glamorous +glamour +glance +glancing +glandular +glare +glaring +glass +glaucoma +glazing +gleaming +gleeful +glider +gliding +glimmer +glimpse +glisten +glitch +glitter +glitzy +gloater +gloating +gloomily +gloomy +glorified +glorifier +glorify +glorious +glory +gloss +glove +glowing +glowworm +glucose +glue +gluten +glutinous +glutton +gnarly +gnat +goal +goatskin +goes +goggles +going +goldfish +goldmine +goldsmith +golf +goliath +gonad +gondola +gone +gong +good +gooey +goofball +goofiness +goofy +google +goon +gopher +gore +gorged +gorgeous +gory +gosling +gossip +gothic +gotten +gout +gown +grab +graceful +graceless +gracious +gradation +graded +grader +gradient +grading +gradually +graduate +graffiti +grafted +grafting +grain +granddad +grandkid +grandly +grandma +grandpa +grandson +granite +granny +granola +grant +granular +grape +graph +grapple +grappling +grasp +grass +gratified +gratify +grating +gratitude +gratuity +gravel +graveness +graves +graveyard +gravitate +gravity +gravy +gray +grazing +greasily +greedily +greedless +greedy +green +greeter +greeting +grew +greyhound +grid +grief +grievance +grieving +grievous +grill +grimace +grimacing +grime +griminess +grimy +grinch +grinning +grip +gristle +grit +groggily +groggy +groin +groom +groove +grooving +groovy +grope +ground +grouped +grout +grove +grower +growing +growl +grub +grudge +grudging +grueling +gruffly +grumble +grumbling +grumbly +grumpily +grunge +grunt +guacamole +guidable +guidance +guide +guiding +guileless +guise +gulf +gullible +gully +gulp +gumball +gumdrop +gumminess +gumming +gummy +gurgle +gurgling +guru +gush +gusto +gusty +gutless +guts +gutter +guy +guzzler +gyration +habitable +habitant +habitat +habitual +hacked +hacker +hacking +hacksaw +had +haggler +haiku +half +halogen +halt +halved +halves +hamburger +hamlet +hammock +hamper +hamster +hamstring +handbag +handball +handbook +handbrake +handcart +handclap +handclasp +handcraft +handcuff +handed +handful +handgrip +handgun +handheld +handiness +handiwork +handlebar +handled +handler +handling +handmade +handoff +handpick +handprint +handrail +handsaw +handset +handsfree +handshake +handstand +handwash +handwork +handwoven +handwrite +handyman +hangnail +hangout +hangover +hangup +hankering +hankie +hanky +haphazard +happening +happier +happiest +happily +happiness +happy +harbor +hardcopy +hardcore +hardcover +harddisk +hardened +hardener +hardening +hardhat +hardhead +hardiness +hardly +hardness +hardship +hardware +hardwired +hardwood +hardy +harmful +harmless +harmonica +harmonics +harmonize +harmony +harness +harpist +harsh +harvest +hash +hassle +haste +hastily +hastiness +hasty +hatbox +hatchback +hatchery +hatchet +hatching +hatchling +hate +hatless +hatred +haunt +haven +hazard +hazelnut +hazily +haziness +hazing +hazy +headache +headband +headboard +headcount +headdress +headed +header +headfirst +headgear +heading +headlamp +headless +headlock +headphone +headpiece +headrest +headroom +headscarf +headset +headsman +headstand +headstone +headway +headwear +heap +heat +heave +heavily +heaviness +heaving +hedge +hedging +heftiness +hefty +helium +helmet +helper +helpful +helping +helpless +helpline +hemlock +hemstitch +hence +henchman +henna +herald +herbal +herbicide +herbs +heritage +hermit +heroics +heroism +herring +herself +hertz +hesitancy +hesitant +hesitate +hexagon +hexagram +hubcap +huddle +huddling +huff +hug +hula +hulk +hull +human +humble +humbling +humbly +humid +humiliate +humility +humming +hummus +humongous +humorist +humorless +humorous +humpback +humped +humvee +hunchback +hundredth +hunger +hungrily +hungry +hunk +hunter +hunting +huntress +huntsman +hurdle +hurled +hurler +hurling +hurray +hurricane +hurried +hurry +hurt +husband +hush +husked +huskiness +hut +hybrid +hydrant +hydrated +hydration +hydrogen +hydroxide +hyperlink +hypertext +hyphen +hypnoses +hypnosis +hypnotic +hypnotism +hypnotist +hypnotize +hypocrisy +hypocrite +ibuprofen +ice +iciness +icing +icky +icon +icy +idealism +idealist +idealize +ideally +idealness +identical +identify +identity +ideology +idiocy +idiom +idly +igloo +ignition +ignore +iguana +illicitly +illusion +illusive +image +imaginary +imagines +imaging +imbecile +imitate +imitation +immature +immerse +immersion +imminent +immobile +immodest +immorally +immortal +immovable +immovably +immunity +immunize +impaired +impale +impart +impatient +impeach +impeding +impending +imperfect +imperial +impish +implant +implement +implicate +implicit +implode +implosion +implosive +imply +impolite +important +importer +impose +imposing +impotence +impotency +impotent +impound +imprecise +imprint +imprison +impromptu +improper +improve +improving +improvise +imprudent +impulse +impulsive +impure +impurity +iodine +iodize +ion +ipad +iphone +ipod +irate +irk +iron +irregular +irrigate +irritable +irritably +irritant +irritate +islamic +islamist +isolated +isolating +isolation +isotope +issue +issuing +italicize +italics +item +itinerary +itunes +ivory +ivy +jab +jackal +jacket +jackknife +jackpot +jailbird +jailbreak +jailer +jailhouse +jalapeno +jam +janitor +january +jargon +jarring +jasmine +jaundice +jaunt +java +jawed +jawless +jawline +jaws +jaybird +jaywalker +jazz +jeep +jeeringly +jellied +jelly +jersey +jester +jet +jiffy +jigsaw +jimmy +jingle +jingling +jinx +jitters +jittery +job +jockey +jockstrap +jogger +jogging +john +joining +jokester +jokingly +jolliness +jolly +jolt +jot +jovial +joyfully +joylessly +joyous +joyride +joystick +jubilance +jubilant +judge +judgingly +judicial +judiciary +judo +juggle +juggling +jugular +juice +juiciness +juicy +jujitsu +jukebox +july +jumble +jumbo +jump +junction +juncture +june +junior +juniper +junkie +junkman +junkyard +jurist +juror +jury +justice +justifier +justify +justly +justness +juvenile +kabob +kangaroo +karaoke +karate +karma +kebab +keenly +keenness +keep +keg +kelp +kennel +kept +kerchief +kerosene +kettle +kick +kiln +kilobyte +kilogram +kilometer +kilowatt +kilt +kimono +kindle +kindling +kindly +kindness +kindred +kinetic +kinfolk +king +kinship +kinsman +kinswoman +kissable +kisser +kissing +kitchen +kite +kitten +kitty +kiwi +kleenex +knapsack +knee +knelt +knickers +knoll +koala +kooky +kosher +krypton +kudos +kung +labored +laborer +laboring +laborious +labrador +ladder +ladies +ladle +ladybug +ladylike +lagged +lagging +lagoon +lair +lake +lance +landed +landfall +landfill +landing +landlady +landless +landline +landlord +landmark +landmass +landmine +landowner +landscape +landside +landslide +language +lankiness +lanky +lantern +lapdog +lapel +lapped +lapping +laptop +lard +large +lark +lash +lasso +last +latch +late +lather +latitude +latrine +latter +latticed +launch +launder +laundry +laurel +lavender +lavish +laxative +lazily +laziness +lazy +lecturer +left +legacy +legal +legend +legged +leggings +legible +legibly +legislate +lego +legroom +legume +legwarmer +legwork +lemon +lend +length +lens +lent +leotard +lesser +letdown +lethargic +lethargy +letter +lettuce +level +leverage +levers +levitate +levitator +liability +liable +liberty +librarian +library +licking +licorice +lid +life +lifter +lifting +liftoff +ligament +likely +likeness +likewise +liking +lilac +lilly +lily +limb +limeade +limelight +limes +limit +limping +limpness +line +lingo +linguini +linguist +lining +linked +linoleum +linseed +lint +lion +lip +liquefy +liqueur +liquid +lisp +list +litigate +litigator +litmus +litter +little +livable +lived +lively +liver +livestock +lividly +living +lizard +lubricant +lubricate +lucid +luckily +luckiness +luckless +lucrative +ludicrous +lugged +lukewarm +lullaby +lumber +luminance +luminous +lumpiness +lumping +lumpish +lunacy +lunar +lunchbox +luncheon +lunchroom +lunchtime +lung +lurch +lure +luridness +lurk +lushly +lushness +luster +lustfully +lustily +lustiness +lustrous +lusty +luxurious +luxury +lying +lyrically +lyricism +lyricist +lyrics +macarena +macaroni +macaw +mace +machine +machinist +magazine +magenta +maggot +magical +magician +magma +magnesium +magnetic +magnetism +magnetize +magnifier +magnify +magnitude +magnolia +mahogany +maimed +majestic +majesty +majorette +majority +makeover +maker +makeshift +making +malformed +malt +mama +mammal +mammary +mammogram +manager +managing +manatee +mandarin +mandate +mandatory +mandolin +manger +mangle +mango +mangy +manhandle +manhole +manhood +manhunt +manicotti +manicure +manifesto +manila +mankind +manlike +manliness +manly +manmade +manned +mannish +manor +manpower +mantis +mantra +manual +many +map +marathon +marauding +marbled +marbles +marbling +march +mardi +margarine +margarita +margin +marigold +marina +marine +marital +maritime +marlin +marmalade +maroon +married +marrow +marry +marshland +marshy +marsupial +marvelous +marxism +mascot +masculine +mashed +mashing +massager +masses +massive +mastiff +matador +matchbook +matchbox +matcher +matching +matchless +material +maternal +maternity +math +mating +matriarch +matrimony +matrix +matron +matted +matter +maturely +maturing +maturity +mauve +maverick +maximize +maximum +maybe +mayday +mayflower +moaner +moaning +mobile +mobility +mobilize +mobster +mocha +mocker +mockup +modified +modify +modular +modulator +module +moisten +moistness +moisture +molar +molasses +mold +molecular +molecule +molehill +mollusk +mom +monastery +monday +monetary +monetize +moneybags +moneyless +moneywise +mongoose +mongrel +monitor +monkhood +monogamy +monogram +monologue +monopoly +monorail +monotone +monotype +monoxide +monsieur +monsoon +monstrous +monthly +monument +moocher +moodiness +moody +mooing +moonbeam +mooned +moonlight +moonlike +moonlit +moonrise +moonscape +moonshine +moonstone +moonwalk +mop +morale +morality +morally +morbidity +morbidly +morphine +morphing +morse +mortality +mortally +mortician +mortified +mortify +mortuary +mosaic +mossy +most +mothball +mothproof +motion +motivate +motivator +motive +motocross +motor +motto +mountable +mountain +mounted +mounting +mourner +mournful +mouse +mousiness +moustache +mousy +mouth +movable +move +movie +moving +mower +mowing +much +muck +mud +mug +mulberry +mulch +mule +mulled +mullets +multiple +multiply +multitask +multitude +mumble +mumbling +mumbo +mummified +mummify +mummy +mumps +munchkin +mundane +municipal +muppet mural -misjudged +murkiness +murky +murmuring +muscular +museum +mushily +mushiness +mushroom +mushy +music +musket +muskiness +musky +mustang +mustard +muster +mustiness +musty +mutable +mutate +mutation +mute +mutilated +mutilator +mutiny +mutt +mutual +muzzle +myself +myspace +mystified +mystify +myth +nacho +nag +nail +name +naming +nanny +nanometer +nape +napkin +napped +napping +nappy +narrow +nastily +nastiness +national +native +nativity +natural +nature +naturist +nautical +navigate +navigator +navy +nearby +nearest +nearly +nearness +neatly +neatness +nebula +nebulizer +nectar +negate +negation +negative +neglector +negligee +negligent +negotiate +nemeses +nemesis +neon +nephew +nerd +nervous +nervy +nest +net +neurology +neuron +neurosis +neurotic +neuter +neutron +never +next +nibble +nickname +nicotine +niece +nifty +nimble +nimbly +nineteen +ninetieth +ninja +nintendo +ninth +nuclear +nuclei +nucleus +nugget +nullify +number +numbing +numbly +numbness +numeral +numerate +numerator +numeric +numerous +nuptials +nursery +nursing +nurture +nutcase +nutlike +nutmeg +nutrient +nutshell +nuttiness +nutty +nuzzle +nylon +oaf +oak +oasis +oat +obedience +obedient +obituary +object +obligate +obliged +oblivion +oblivious +oblong +obnoxious +oboe +obscure +obscurity +observant +observer +observing +obsessed +obsession +obsessive +obsolete +obstacle +obstinate +obstruct +obtain +obtrusive +obtuse +obvious +occultist +occupancy +occupant +occupier +occupy +ocean +ocelot +octagon +octane +october +octopus +ogle +oil +oink +ointment +okay +old +olive +olympics +omega +omen +ominous +omission +omit +omnivore +onboard +oncoming +ongoing +onion +online +onlooker +only +onscreen +onset +onshore +onslaught +onstage +onto +onward +onyx +oops +ooze +oozy +opacity +opal +open +operable +operate +operating +operation +operative +operator +opium +opossum +opponent +oppose +opposing +opposite +oppressed +oppressor +opt +opulently +osmosis +other +otter +ouch +ought +ounce +outage +outback +outbid +outboard +outbound +outbreak +outburst +outcast +outclass +outcome +outdated +outdoors +outer +outfield +outfit +outflank +outgoing +outgrow +outhouse +outing +outlast +outlet +outline +outlook +outlying +outmatch +outmost +outnumber +outplayed +outpost +outpour +output +outrage +outrank +outreach +outright +outscore +outsell +outshine +outshoot +outsider +outskirts +outsmart +outsource +outspoken +outtakes +outthink +outward +outweigh +outwit +oval +ovary +oven +overact +overall +overarch +overbid +overbill +overbite +overblown +overboard +overbook +overbuilt +overcast +overcoat +overcome +overcook +overcrowd +overdraft +overdrawn +overdress +overdrive +overdue +overeager +overeater +overexert +overfed +overfeed +overfill +overflow +overfull +overgrown +overhand +overhang +overhaul +overhead +overhear +overheat +overhung +overjoyed +overkill +overlabor +overlaid +overlap +overlay +overload +overlook +overlord +overlying +overnight +overpass +overpay +overplant +overplay +overpower +overprice +overrate +overreach +overreact +override +overripe +overrule +overrun +overshoot +overshot +oversight +oversized +oversleep +oversold +overspend +overstate +overstay +overstep +overstock +overstuff +oversweet +overtake +overthrow +overtime +overtly +overtone +overture +overturn +overuse +overvalue +overview +overwrite +owl +oxford +oxidant +oxidation +oxidize +oxidizing +oxygen +oxymoron +oyster +ozone +paced +pacemaker +pacific +pacifier +pacifism +pacifist +pacify +padded +padding +paddle +paddling +padlock +pagan +pager +paging +pajamas +palace +palatable +palm +palpable +palpitate +paltry +pampered +pamperer +pampers +pamphlet +panama +pancake +pancreas +panda +pandemic +pang +panhandle +panic +panning +panorama +panoramic +panther +pantomime +pantry +pants +pantyhose +paparazzi +papaya +paper +paprika +papyrus +parabola +parachute +parade +paradox +paragraph +parakeet +paralegal +paralyses +paralysis +paralyze +paramedic +parameter +paramount +parasail +parasite +parasitic +parcel +parched +parchment +pardon +parish +parka +parking +parkway +parlor +parmesan +parole +parrot +parsley +parsnip +partake +parted +parting +partition +partly +partner +partridge +party +passable +passably +passage +passcode +passenger +passerby +passing +passion +passive +passivism +passover +passport +password +pasta +pasted +pastel +pastime +pastor +pastrami +pasture +pasty +patchwork +patchy +paternal +paternity +path +patience +patient +patio +patriarch +patriot +patrol +patronage +patronize +pauper +pavement +paver +pavestone +pavilion +paving +pawing +payable +payback +paycheck +payday +payee +payer +paying +payment +payphone +payroll +pebble +pebbly +pecan +pectin +peculiar +peddling +pediatric +pedicure +pedigree +pedometer +pegboard +pelican +pellet +pelt +pelvis +penalize +penalty +pencil +pendant +pending +penholder +penknife +pennant +penniless +penny +penpal +pension +pentagon +pentagram +pep +perceive +percent +perch +percolate +perennial +perfected +perfectly +perfume +periscope +perish +perjurer +perjury +perkiness +perky +perm +peroxide +perpetual +perplexed +persecute +persevere +persuaded +persuader +pesky +peso +pessimism +pessimist +pester +pesticide +petal +petite +petition +petri +petroleum +petted +petticoat +pettiness +petty +petunia +phantom +phobia +phoenix +phonebook +phoney +phonics +phoniness +phony +phosphate +photo +phrase +phrasing +placard +placate +placidly +plank +planner +plant +plasma +plaster +plastic +plated +platform +plating +platinum +platonic +platter +platypus +plausible +plausibly +playable +playback +player +playful +playgroup +playhouse +playing +playlist +playmaker +playmate +playoff +playpen +playroom +playset +plaything +playtime +plaza +pleading +pleat +pledge +plentiful +plenty +plethora +plexiglas +pliable +plod +plop +plot +plow +ploy +pluck +plug +plunder +plunging +plural +plus +plutonium +plywood +poach +pod +poem +poet +pogo +pointed +pointer +pointing +pointless +pointy +poise +poison +poker +poking +polar +police +policy +polio +polish +politely +polka +polo +polyester +polygon +polygraph +polymer +poncho +pond +pony +popcorn +pope +poplar +popper +poppy +popsicle +populace +popular +populate +porcupine +pork +porous +porridge +portable +portal +portfolio +porthole +portion +portly +portside +poser +posh +posing +possible +possibly +possum +postage +postal +postbox +postcard +posted +poster +posting +postnasal +posture +postwar +pouch +pounce +pouncing +pound +pouring +pout +powdered +powdering +powdery +power +powwow +pox +praising +prance +prancing +pranker +prankish +prankster +prayer +praying +preacher +preaching +preachy +preamble +precinct +precise +precision +precook +precut +predator +predefine +predict +preface +prefix +preflight +preformed +pregame +pregnancy +pregnant +preheated +prelaunch +prelaw +prelude +premiere +premises +premium +prenatal +preoccupy +preorder +prepaid +prepay +preplan +preppy +preschool +prescribe +preseason +preset +preshow +president +presoak +press +presume +presuming +preteen +pretended +pretender +pretense +pretext +pretty +pretzel +prevail +prevalent +prevent +preview +previous +prewar +prewashed +prideful +pried +primal +primarily +primary +primate +primer +primp +princess +print +prior +prism +prison +prissy +pristine +privacy +private +privatize +prize +proactive +probable +probably +probation +probe +probing +probiotic +problem +procedure +process +proclaim +procreate +procurer +prodigal +prodigy +produce +product +profane +profanity +professed +professor +profile +profound +profusely +progeny +prognosis +program +progress +projector +prologue +prolonged +promenade +prominent +promoter +promotion +prompter +promptly +prone +prong +pronounce +pronto +proofing +proofread +proofs +propeller +properly +property +proponent +proposal +propose +props +prorate +protector +protegee +proton +prototype +protozoan +protract +protrude +proud +provable +proved +proven +provided +provider +providing +province +proving +provoke +provoking +provolone +prowess +prowler +prowling +proximity +proxy +prozac +prude +prudishly +prune +pruning +pry +psychic +public +publisher +pucker +pueblo +pug +pull +pulmonary +pulp +pulsate +pulse +pulverize +puma +pumice +pummel +punch +punctual +punctuate +punctured +pungent +punisher +punk +pupil +puppet +puppy +purchase +pureblood +purebred +purely +pureness +purgatory +purge +purging +purifier +purify +purist +puritan +purity +purple +purplish +purposely +purr +purse +pursuable +pursuant +pursuit +purveyor +pushcart +pushchair +pusher +pushiness +pushing +pushover +pushpin +pushup +pushy +putdown +putt +puzzle +puzzling +pyramid +pyromania +python +quack +quadrant +quail +quaintly +quake +quaking +qualified +qualifier +qualify +quality +qualm +quantum +quarrel +quarry +quartered +quarterly +quarters +quartet +quench +query +quicken +quickly +quickness +quicksand +quickstep +quiet +quill +quilt +quintet +quintuple +quirk +quit +quiver +quizzical +quotable +quotation +quote +rabid +race +racing +racism +rack +racoon +radar +radial +radiance +radiantly +radiated +radiation +radiator +radio +radish +raffle +raft +rage +ragged +raging +ragweed +raider +railcar +railing +railroad +railway +raisin +rake +raking +rally +ramble +rambling +ramp +ramrod +ranch +rancidity +random +ranged +ranger +ranging +ranked +ranking +ransack +ranting +rants +rare +rarity +rascal +rash +rasping +ravage +raven +ravine +raving +ravioli +ravishing +reabsorb +reach +reacquire +reaction +reactive +reactor +reaffirm +ream +reanalyze +reappear +reapply +reappoint +reapprove +rearrange +rearview +reason +reassign +reassure +reattach +reawake +rebalance +rebate +rebel +rebirth +reboot +reborn +rebound +rebuff +rebuild +rebuilt +reburial +rebuttal +recall +recant +recapture +recast +recede +recent +recess +recharger +recipient +recital +recite +reckless +reclaim +recliner +reclining +recluse +reclusive +recognize +recoil +recollect +recolor +reconcile +reconfirm +reconvene +recopy +record +recount +recoup +recovery +recreate +rectal +rectangle +rectified +rectify +recycled +recycler +recycling +reemerge +reenact +reenter +reentry +reexamine +referable +referee +reference +refill +refinance +refined +refinery +refining +refinish +reflected +reflector +reflex +reflux +refocus +refold +reforest +reformat +reformed +reformer +reformist +refract +refrain +refreeze +refresh +refried +refueling +refund +refurbish +refurnish +refusal +refuse +refusing +refutable +refute +regain +regalia +regally +reggae +regime +region +register +registrar +registry +regress +regretful +regroup +regular +regulate +regulator +rehab +reheat +rehire +rehydrate +reimburse +reissue +reiterate +rejoice +rejoicing +rejoin +rekindle +relapse +relapsing +relatable +related +relation +relative +relax +relay +relearn +release +relenting +reliable +reliably +reliance +reliant +relic +relieve +relieving +relight +relish +relive +reload +relocate +relock +reluctant +rely +remake +remark +remarry +rematch +remedial +remedy +remember +reminder +remindful +remission +remix +remnant +remodeler +remold +remorse +remote +removable +removal +removed +remover +removing +rename +renderer +rendering +rendition +renegade +renewable +renewably +renewal +renewed +renounce +renovate +renovator +rentable +rental +rented +renter +reoccupy +reoccur +reopen +reorder +repackage +repacking +repaint +repair +repave +repaying +repayment +repeal +repeated +repeater +repent +rephrase +replace +replay +replica +reply +reporter +repose +repossess +repost +repressed +reprimand +reprint +reprise +reproach +reprocess +reproduce +reprogram +reps +reptile +reptilian +repugnant +repulsion +repulsive +repurpose +reputable +reputably +request +require +requisite +reroute +rerun +resale +resample +rescuer +reseal +research +reselect +reseller +resemble +resend +resent +reset +reshape +reshoot +reshuffle +residence +residency +resident +residual +residue +resigned +resilient +resistant +resisting +resize +resolute +resolved +resonant +resonate +resort +resource +respect +resubmit +result +resume +resupply +resurface +resurrect +retail +retainer +retaining +retake +retaliate +retention +rethink +retinal +retired +retiree +retiring +retold +retool +retorted +retouch +retrace +retract +retrain +retread +retreat +retrial +retrieval +retriever +retry +return +retying +retype +reunion +reunite +reusable +reuse +reveal +reveler +revenge +revenue +reverb +revered +reverence +reverend +reversal +reverse +reversing +reversion +revert +revisable +revise +revision +revisit +revivable +revival +reviver +reviving +revocable +revoke +revolt +revolver +revolving +reward +rewash +rewind +rewire +reword +rework +rewrap +rewrite +rhyme +ribbon +ribcage +rice +riches +richly +richness +rickety +ricotta +riddance +ridden +ride +riding +rifling +rift +rigging +rigid +rigor +rimless +rimmed +rind +rink +rinse +rinsing +riot +ripcord +ripeness +ripening +ripping +ripple +rippling +riptide +rise +rising +risk +risotto +ritalin +ritzy +rival +riverbank +riverbed +riverboat +riverside +riveter +riveting +roamer +roaming +roast +robbing +robe +robin +robotics +robust +rockband +rocker +rocket +rockfish +rockiness +rocking +rocklike +rockslide +rockstar +rocky +rogue +roman +romp +rope +roping +roster +rosy +rotten +rotting +rotunda +roulette +rounding +roundish +roundness +roundup +roundworm +routine +routing +rover +roving +royal +rubbed +rubber +rubbing +rubble +rubdown +ruby +ruckus +rudder +rug +ruined +rule +rumble +rumbling +rummage +rumor +runaround +rundown +runner +running +runny +runt +runway +rupture +rural +ruse +rush +rust +rut +sabbath +sabotage +sacrament +sacred +sacrifice +sadden +saddlebag +saddled +saddling +sadly +sadness +safari +safeguard +safehouse +safely +safeness +saffron +saga +sage +sagging +saggy +said +saint +sake +salad +salami +salaried +salary +saline +salon +saloon +salsa +salt +salutary +salute +salvage +salvaging +salvation +same +sample +sampling +sanction +sanctity +sanctuary +sandal +sandbag +sandbank +sandbar +sandblast +sandbox +sanded +sandfish +sanding +sandlot +sandpaper +sandpit +sandstone +sandstorm +sandworm +sandy +sanitary +sanitizer +sank +santa +sapling +sappiness +sappy +sarcasm +sarcastic +sardine +sash +sasquatch +sassy +satchel +satiable +satin +satirical +satisfied +satisfy +saturate +saturday +sauciness +saucy +sauna +savage +savanna +saved +savings +savior +savor +saxophone +say +scabbed +scabby +scalded +scalding +scale +scaling +scallion +scallop +scalping +scam +scandal +scanner +scanning +scant +scapegoat +scarce +scarcity +scarecrow +scared +scarf +scarily +scariness +scarring +scary +scavenger +scenic +schedule +schematic +scheme +scheming +schilling +schnapps +scholar +science +scientist +scion +scoff +scolding +scone +scoop +scooter +scope +scorch +scorebook +scorecard +scored +scoreless +scorer +scoring +scorn +scorpion +scotch +scoundrel +scoured +scouring +scouting +scouts +scowling +scrabble +scraggly +scrambled +scrambler +scrap +scratch +scrawny +screen +scribble +scribe +scribing +scrimmage +script +scroll +scrooge +scrounger +scrubbed +scrubber +scruffy +scrunch +scrutiny +scuba +scuff +sculptor +sculpture +scurvy +scuttle +secluded +secluding +seclusion +second +secrecy +secret +sectional +sector +secular +securely +security +sedan +sedate +sedation +sedative +sediment +seduce +seducing +segment +seismic +seizing +seldom +selected +selection +selective +selector +self +seltzer +semantic +semester +semicolon +semifinal +seminar +semisoft +semisweet +senate +senator +send +senior +senorita +sensation +sensitive +sensitize +sensually +sensuous +sepia +september +septic +septum +sequel +sequence +sequester +series +sermon +serotonin +serpent +serrated +serve +service +serving +sesame +sessions +setback +setting +settle +settling +setup +sevenfold +seventeen +seventh +seventy +severity +shabby +shack +shaded +shadily +shadiness +shading +shadow +shady +shaft +shakable +shakily +shakiness +shaking +shaky +shale +shallot +shallow +shame +shampoo +shamrock +shank +shanty +shape +shaping +share +sharpener +sharper +sharpie +sharply +sharpness +shawl +sheath +shed +sheep +sheet +shelf +shell +shelter +shelve +shelving +sherry +shield +shifter +shifting +shiftless +shifty +shimmer +shimmy +shindig +shine +shingle +shininess +shining +shiny +ship +shirt +shivering +shock +shone +shoplift +shopper +shopping +shoptalk +shore +shortage +shortcake +shortcut +shorten +shorter +shorthand +shortlist +shortly +shortness +shorts +shortwave +shorty +shout +shove +showbiz +showcase +showdown +shower +showgirl +showing +showman +shown +showoff +showpiece +showplace +showroom +showy +shrank +shrapnel +shredder +shredding +shrewdly +shriek +shrill +shrimp +shrine +shrink +shrivel +shrouded +shrubbery +shrubs +shrug +shrunk +shucking +shudder +shuffle +shuffling +shun +shush +shut +shy +siamese +siberian +sibling +siding +sierra +siesta +sift +sighing +silenced +silencer +silent +silica +silicon +silk +silliness +silly +silo +silt +silver +similarly +simile +simmering +simple +simplify +simply +sincere +sincerity +singer +singing +single +singular +sinister +sinless +sinner +sinuous +sip +siren +sister +sitcom +sitter +sitting +situated +situation +sixfold +sixteen +sixth +sixties +sixtieth +sixtyfold +sizable +sizably +size +sizing +sizzle +sizzling +skater +skating +skedaddle +skeletal +skeleton +skeptic +sketch +skewed +skewer +skid +skied +skier +skies +skiing +skilled +skillet +skillful +skimmed +skimmer +skimming +skimpily +skincare +skinhead +skinless +skinning +skinny +skintight +skipper +skipping +skirmish +skirt +skittle +skydiver +skylight +skyline +skype +skyrocket +skyward +slab +slacked +slacker +slacking +slackness +slacks +slain +slam +slander +slang +slapping +slapstick +slashed +slashing +slate +slather +slaw +sled +sleek +sleep +sleet +sleeve +slept +sliceable +sliced +slicer +slicing +slick +slider +slideshow +sliding +slighted +slighting +slightly +slimness +slimy +slinging +slingshot +slinky +slip +slit +sliver +slobbery +slogan +sloped +sloping +sloppily +sloppy +slot +slouching +slouchy +sludge +slug +slum +slurp +slush +sly +small +smartly +smartness +smasher +smashing +smashup +smell +smelting +smile +smilingly +smirk +smite +smith +smitten +smock +smog +smoked +smokeless +smokiness +smoking +smoky +smolder +smooth +smother +smudge +smudgy +smuggler +smuggling +smugly +smugness +snack +snagged +snaking +snap +snare +snarl +snazzy +sneak +sneer +sneeze +sneezing +snide +sniff +snippet +snipping +snitch +snooper +snooze +snore +snoring +snorkel +snort +snout +snowbird +snowboard +snowbound +snowcap +snowdrift +snowdrop +snowfall +snowfield +snowflake +snowiness +snowless +snowman +snowplow +snowshoe +snowstorm +snowsuit +snowy +snub +snuff +snuggle +snugly +snugness +speak +spearfish +spearhead +spearman +spearmint +species +specimen +specked +speckled +specks +spectacle +spectator +spectrum +speculate +speech +speed +spellbind +speller +spelling +spendable +spender +spending +spent +spew +sphere +spherical +sphinx +spider +spied +spiffy +spill +spilt +spinach +spinal +spindle +spinner +spinning +spinout +spinster +spiny +spiral +spirited +spiritism +spirits +spiritual +splashed +splashing +splashy +splatter +spleen +splendid +splendor +splice +splicing +splinter +splotchy +splurge +spoilage +spoiled +spoiler +spoiling +spoils +spoken +spokesman +sponge +spongy +sponsor +spoof +spookily +spooky +spool +spoon +spore +sporting +sports +sporty +spotless +spotlight +spotted +spotter +spotting +spotty +spousal +spouse +spout +sprain +sprang +sprawl +spray +spree +sprig +spring +sprinkled +sprinkler +sprint +sprite +sprout +spruce +sprung +spry +spud +spur +sputter +spyglass +squabble +squad +squall +squander +squash +squatted +squatter +squatting +squeak +squealer +squealing +squeamish +squeegee +squeeze +squeezing +squid +squiggle +squiggly +squint +squire +squirt +squishier +squishy +stability +stabilize +stable +stack +stadium +staff +stage +staging +stagnant +stagnate +stainable +stained +staining +stainless +stalemate +staleness +stalling +stallion +stamina +stammer +stamp +stand +stank +staple +stapling +starboard +starch +stardom +stardust +starfish +stargazer +staring +stark +starless +starlet +starlight +starlit +starring +starry +starship +starter +starting +startle +startling +startup +starved +starving +stash +state +static +statistic +statue +stature +status +statute +statutory +staunch +stays +steadfast +steadier +steadily +steadying +steam +steed +steep +steerable +steering +steersman +stegosaur +stellar +stem +stench +stencil +step +stereo +sterile +sterility +sterilize +sterling +sternness +sternum +stew +stick +stiffen +stiffly +stiffness +stifle +stifling +stillness +stilt +stimulant +stimulate +stimuli +stimulus +stinger +stingily +stinging +stingray +stingy +stinking +stinky +stipend +stipulate +stir +stitch +stock +stoic +stoke +stole +stomp +stonewall +stoneware +stonework +stoning +stony +stood +stooge +stool +stoop +stoplight +stoppable +stoppage +stopped +stopper +stopping +stopwatch +storable +storage +storeroom +storewide +storm +stout +stove +stowaway +stowing +straddle +straggler +strained +strainer +straining +strangely +stranger +strangle +strategic +strategy +stratus +straw +stray +streak +stream +street +strength +strenuous +strep +stress +stretch +strewn +stricken +strict +stride +strife +strike +striking +strive +striving +strobe +strode +stroller +strongbox +strongly +strongman +struck +structure +strudel +struggle +strum +strung +strut +stubbed +stubble +stubbly +stubborn +stucco +stuck +student +studied +studio +study +stuffed +stuffing +stuffy +stumble +stumbling +stump +stung +stunned +stunner +stunning +stunt +stupor +sturdily +sturdy +styling +stylishly +stylist +stylized +stylus +suave +subarctic +subatomic +subdivide +subdued +subduing +subfloor +subgroup +subheader +subject +sublease +sublet +sublevel +sublime +submarine +submerge +submersed +submitter +subpanel +subpar +subplot +subprime +subscribe +subscript +subsector +subside +subsiding +subsidize +subsidy +subsoil +subsonic +substance +subsystem +subtext +subtitle +subtly +subtotal +subtract +subtype +suburb +subway +subwoofer +subzero +succulent +such +suction +sudden +sudoku +suds +sufferer +suffering +suffice +suffix +suffocate +suffrage +sugar +suggest +suing +suitable +suitably +suitcase +suitor +sulfate +sulfide +sulfite +sulfur +sulk +sullen +sulphate +sulphuric +sultry +superbowl +superglue +superhero +superior +superjet +superman +supermom +supernova +supervise +supper +supplier +supply +support +supremacy +supreme +surcharge +surely +sureness +surface +surfacing +surfboard +surfer +surgery +surgical +surging +surname +surpass +surplus +surprise +surreal +surrender +surrogate +surround +survey +survival +survive +surviving +survivor +sushi +suspect +suspend +suspense +sustained +sustainer +swab +swaddling +swagger +swampland +swan +swapping +swarm +sway +swear +sweat +sweep +swell +swept +swerve +swifter +swiftly +swiftness +swimmable +swimmer +swimming +swimsuit +swimwear +swinger +swinging +swipe +swirl +switch +swivel +swizzle +swooned +swoop +swoosh +swore +sworn +swung +sycamore +sympathy +symphonic +symphony +symptom +synapse +syndrome +synergy +synopses +synopsis +synthesis +synthetic +syrup +system +t-shirt +tabasco +tabby +tableful +tables +tablet +tableware +tabloid +tackiness +tacking +tackle +tackling +tacky +taco +tactful +tactical +tactics +tactile +tactless +tadpole +taekwondo +tag +tainted +take +taking +talcum +talisman +tall +talon +tamale +tameness +tamer +tamper +tank +tanned +tannery +tanning +tantrum +tapeless +tapered +tapering +tapestry +tapioca +tapping +taps +tarantula +target +tarmac +tarnish +tarot +tartar +tartly +tartness +task +tassel +taste +tastiness +tasting +tasty +tattered +tattle +tattling +tattoo +taunt +tavern +thank +that +thaw +theater +theatrics +thee +theft +theme +theology +theorize +thermal +thermos +thesaurus +these +thesis +thespian +thicken +thicket +thickness +thieving +thievish +thigh +thimble +thing +think +thinly +thinner +thinness +thinning +thirstily +thirsting +thirsty +thirteen +thirty +thong +thorn +those +thousand +thrash +thread +threaten +threefold +thrift +thrill +thrive +thriving +throat +throbbing +throng +throttle +throwaway +throwback +thrower +throwing +thud +thumb +thumping +thursday +thus +thwarting +thyself +tiara +tibia +tidal +tidbit +tidiness +tidings +tidy +tiger +tighten +tightly +tightness +tightrope +tightwad +tigress +tile +tiling +till +tilt +timid +timing +timothy +tinderbox +tinfoil +tingle +tingling +tingly +tinker +tinkling +tinsel +tinsmith +tint +tinwork +tiny +tipoff +tipped +tipper +tipping +tiptoeing +tiptop +tiring +tissue +trace +tracing +track +traction +tractor +trade +trading +tradition +traffic +tragedy +trailing +trailside +train +traitor +trance +tranquil +transfer +transform +translate +transpire +transport +transpose +trapdoor +trapeze +trapezoid +trapped +trapper +trapping +traps +trash +travel +traverse +travesty +tray +treachery +treading +treadmill +treason +treat +treble +tree +trekker +tremble +trembling +tremor +trench +trend +trespass +triage +trial +triangle +tribesman +tribunal +tribune +tributary +tribute +triceps +trickery +trickily +tricking +trickle +trickster +tricky +tricolor +tricycle +trident +tried +trifle +trifocals +trillion +trilogy +trimester +trimmer +trimming +trimness +trinity +trio +tripod +tripping +triumph +trivial +trodden +trolling +trombone +trophy +tropical +tropics +trouble +troubling +trough +trousers +trout +trowel +truce +truck +truffle +trump +trunks +trustable +trustee +trustful +trusting +trustless +truth +try +tubby +tubeless +tubular +tucking +tuesday +tug +tuition +tulip +tumble +tumbling +tummy +turban +turbine +turbofan +turbojet +turbulent +turf +turkey +turmoil +turret +turtle +tusk +tutor +tutu +tux +tweak +tweed +tweet +tweezers +twelve +twentieth +twenty +twerp +twice +twiddle +twiddling +twig +twilight +twine +twins +twirl +twistable +twisted +twister +twisting +twisty +twitch +twitter +tycoon +tying +tyke +udder +ultimate +ultimatum +ultra +umbilical +umbrella +umpire +unabashed +unable +unadorned +unadvised +unafraid +unaired +unaligned +unaltered +unarmored +unashamed +unaudited +unawake +unaware +unbaked +unbalance +unbeaten +unbend +unbent +unbiased +unbitten +unblended +unblessed +unblock +unbolted +unbounded +unboxed +unbraided +unbridle +unbroken +unbuckled +unbundle +unburned +unbutton +uncanny +uncapped +uncaring +uncertain +unchain +unchanged +uncharted +uncheck +uncivil +unclad +unclaimed +unclamped +unclasp +uncle +unclip +uncloak +unclog +unclothed +uncoated +uncoiled +uncolored +uncombed +uncommon +uncooked +uncork +uncorrupt +uncounted +uncouple +uncouth +uncover +uncross +uncrown +uncrushed +uncured +uncurious +uncurled +uncut +undamaged +undated +undaunted +undead +undecided +undefined +underage +underarm +undercoat +undercook +undercut +underdog +underdone +underfed +underfeed +underfoot +undergo +undergrad +underhand +underline +underling +undermine +undermost +underpaid +underpass +underpay +underrate +undertake +undertone +undertook +undertow +underuse +underwear +underwent +underwire +undesired +undiluted +undivided +undocked +undoing +undone +undrafted +undress +undrilled +undusted +undying +unearned +unearth +unease +uneasily +uneasy +uneatable +uneaten +unedited +unelected +unending +unengaged +unenvied +unequal +unethical +uneven +unexpired +unexposed +unfailing +unfair +unfasten +unfazed +unfeeling +unfiled +unfilled +unfitted +unfitting +unfixable +unfixed +unflawed +unfocused +unfold +unfounded +unframed +unfreeze +unfrosted +unfrozen +unfunded +unglazed +ungloved +unglue +ungodly +ungraded +ungreased +unguarded +unguided +unhappily +unhappy +unharmed +unhealthy +unheard +unhearing +unheated +unhelpful +unhidden +unhinge +unhitched +unholy +unhook +unicorn +unicycle +unified +unifier +uniformed +uniformly +unify +unimpeded +uninjured +uninstall +uninsured +uninvited +union +uniquely +unisexual +unison +unissued +unit +universal +universe +unjustly +unkempt +unkind +unknotted +unknowing +unknown +unlaced +unlatch +unlawful +unleaded +unlearned +unleash +unless +unleveled +unlighted +unlikable +unlimited +unlined +unlinked +unlisted +unlit +unlivable +unloaded +unloader +unlocked +unlocking +unlovable +unloved +unlovely +unloving +unluckily +unlucky +unmade +unmanaged +unmanned +unmapped +unmarked +unmasked +unmasking +unmatched +unmindful +unmixable +unmixed +unmolded +unmoral +unmovable +unmoved +unmoving +unnamable +unnamed +unnatural +unneeded +unnerve +unnerving +unnoticed +unopened +unopposed +unpack +unpadded +unpaid +unpainted +unpaired +unpaved +unpeeled +unpicked +unpiloted +unpinned +unplanned +unplanted +unpleased +unpledged +unplowed +unplug +unpopular +unproven +unquote +unranked +unrated +unraveled +unreached +unread +unreal +unreeling +unrefined +unrelated +unrented +unrest +unretired +unrevised +unrigged +unripe +unrivaled +unroasted +unrobed +unroll +unruffled +unruly +unrushed +unsaddle +unsafe +unsaid +unsalted +unsaved +unsavory +unscathed +unscented +unscrew +unsealed +unseated +unsecured +unseeing +unseemly +unseen +unselect +unselfish +unsent +unsettled +unshackle +unshaken +unshaved +unshaven +unsheathe +unshipped +unsightly +unsigned +unskilled +unsliced +unsmooth +unsnap +unsocial +unsoiled +unsold +unsolved +unsorted +unspoiled +unspoken +unstable +unstaffed +unstamped +unsteady +unsterile +unstirred +unstitch +unstopped +unstuck +unstuffed +unstylish +unsubtle +unsubtly +unsuited +unsure +unsworn +untagged +untainted +untaken +untamed +untangled +untapped +untaxed +unthawed +unthread +untidy +untie +until +untimed +untimely +untitled +untoasted +untold +untouched +untracked +untrained +untreated +untried +untrimmed +untrue +untruth +unturned +untwist +untying +unusable +unused +unusual +unvalued +unvaried +unvarying +unveiled +unveiling +unvented +unviable +unvisited +unvocal +unwanted +unwarlike +unwary +unwashed +unwatched +unweave +unwed +unwelcome +unwell +unwieldy +unwilling +unwind +unwired +unwitting +unwomanly +unworldly +unworn +unworried +unworthy +unwound +unwoven +unwrapped +unwritten +unzip +upbeat +upchuck +upcoming +upcountry +update +upfront +upgrade +upheaval +upheld +uphill +uphold +uplifted +uplifting +upload +upon +upper +upright +uprising +upriver +uproar +uproot +upscale +upside +upstage +upstairs +upstart +upstate +upstream +upstroke +upswing +uptake +uptight +uptown +upturned +upward +upwind +uranium +urban +urchin +urethane +urgency +urgent +urging +urologist +urology +usable +usage +useable +used +uselessly +user +usher +usual +utensil +utility +utilize +utmost +utopia +utter +vacancy +vacant +vacate +vacation +vagabond +vagrancy +vagrantly +vaguely +vagueness +valiant +valid +valium +valley +valuables +value +vanilla +vanish +vanity +vanquish +vantage +vaporizer +variable +variably +varied +variety +various +varmint +varnish +varsity +varying +vascular +vaseline +vastly +vastness +veal +vegan +veggie +vehicular +velcro +velocity +velvet +vendetta +vending +vendor +veneering +vengeful +venomous +ventricle +venture +venue +venus +verbalize +verbally +verbose +verdict +verify +verse +version +versus +vertebrae +vertical +vertigo +very +vessel +vest +veteran +veto +vexingly +viability +viable +vibes +vice +vicinity +victory +video +viewable +viewer +viewing +viewless +viewpoint +vigorous +village +villain +vindicate +vineyard +vintage +violate +violation +violator +violet +violin +viper +viral +virtual +virtuous +virus +visa +viscosity +viscous +viselike +visible +visibly +vision +visiting +visitor +visor +vista +vitality +vitalize +vitally +vitamins +vivacious +vividly +vividness +vixen +vocalist +vocalize +vocally +vocation +voice +voicing +void +volatile +volley +voltage +volumes +voter +voting +voucher +vowed +vowel +voyage +wackiness +wad +wafer +waffle +waged +wager +wages +waggle +wagon +wake +waking +walk +walmart +walnut +walrus +waltz +wand +wannabe +wanted +wanting +wasabi +washable +washbasin +washboard +washbowl +washcloth +washday +washed +washer +washhouse +washing +washout +washroom +washstand +washtub +wasp +wasting +watch +water +waviness +waving +wavy +whacking +whacky +wham +wharf +wheat +whenever +whiff +whimsical +whinny +whiny +whisking +whoever +whole +whomever +whoopee +whooping +whoops +why +wick +widely +widen +widget +widow +width +wieldable +wielder +wife +wifi +wikipedia +wildcard +wildcat +wilder +wildfire +wildfowl +wildland +wildlife +wildly +wildness +willed +willfully +willing +willow +willpower +wilt +wimp +wince +wincing +wind +wing +winking +winner +winnings +winter +wipe +wired +wireless +wiring +wiry +wisdom +wise +wish +wisplike +wispy +wistful +wizard +wobble +wobbling +wobbly +wok +wolf +wolverine +womanhood +womankind +womanless +womanlike +womanly +womb +woof +wooing +wool +woozy +word +work +worried +worrier +worrisome +worry +worsening +worshiper +worst +wound +woven +wow +wrangle +wrath +wreath +wreckage +wrecker +wrecking +wrench +wriggle +wriggly +wrinkle +wrinkly +wrist +writing +written +wrongdoer +wronged +wrongful +wrongly +wrongness +wrought +xbox +xerox +yahoo +yam +yanking +yapping +yard +yarn +yeah +yearbook +yearling +yearly +yearning +yeast +yelling +yelp +yen +yesterday +yiddish +yield +yin +yippee +yo-yo +yodel +yoga +yogurt +yonder +yoyo +yummy +zap +zealous +zebra +zen +zeppelin +zero +zestfully +zesty +zigzagged +zipfile +zipping +zippy +zips +zit +zodiac +zombie +zone +zoning +zookeeper +zoologist +zoology +zoom diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 5dab35251..336e72875 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -113,7 +113,7 @@ impl Crypto { let (derived_left_bits, derived_right_bits) = match self.kdf { Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c), - Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r), + Kdf::Scrypt(ref params) => try!(crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r)), }; let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256(); diff --git a/ethstore/src/dir/disk.rs b/ethstore/src/dir/disk.rs index 6616ec15d..56b2c1ccb 100644 --- a/ethstore/src/dir/disk.rs +++ b/ethstore/src/dir/disk.rs @@ -20,6 +20,7 @@ use std::collections::HashMap; use time; use ethkey::Address; use {json, SafeAccount, Error}; +use json::UUID; use super::KeyDirectory; const IGNORED_FILES: &'static [&'static str] = &["thumbs.db", "address_book.json"]; @@ -112,7 +113,7 @@ impl KeyDirectory for DiskDirectory { // build file path let filename = account.filename.as_ref().cloned().unwrap_or_else(|| { let timestamp = time::strftime("%Y-%m-%dT%H-%M-%S", &time::now_utc()).expect("Time-format string is valid."); - format!("UTC--{}Z--{:?}", timestamp, account.address) + format!("UTC--{}Z--{}", timestamp, UUID::from(account.id)) }); // update account filename diff --git a/js/package.json b/js/package.json index 3d3d312e9..af56140b1 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.35", + "version": "0.2.52", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", @@ -122,6 +122,7 @@ "brace": "^0.9.0", "bytes": "^2.4.0", "chart.js": "^2.3.0", + "es6-error": "^4.0.0", "es6-promise": "^3.2.1", "ethereumjs-tx": "^1.1.2", "file-saver": "^1.3.3", @@ -138,6 +139,7 @@ "mobx-react": "^3.5.8", "mobx-react-devtools": "^4.2.9", "moment": "^2.14.1", + "phoneformat.js": "^1.0.3", "qs": "^6.3.0", "react": "^15.2.1", "react-ace": "^4.0.0", diff --git a/js/scripts/release.sh b/js/scripts/release.sh index 5e631cf98..3ff4a577c 100755 --- a/js/scripts/release.sh +++ b/js/scripts/release.sh @@ -68,11 +68,13 @@ if [ "$BRANCH" == "master" ]; then fi echo "*** Updating cargo parity-ui-precompiled#$PRECOMPILED_HASH" +git submodule update cargo update -p parity-ui-precompiled # --precise "$PRECOMPILED_HASH" echo "*** Committing updated files" -git add . +git add js +git add Cargo.lock git commit -m "[ci skip] js-precompiled $UTCDATE" git push origin HEAD:refs/heads/$BRANCH 2>$GITLOG diff --git a/js/src/abi/util/pad.js b/js/src/abi/util/pad.js index a7d940431..5a6751a4f 100644 --- a/js/src/abi/util/pad.js +++ b/js/src/abi/util/pad.js @@ -46,7 +46,8 @@ function stringToBytes (input) { if (isArray(input)) { return input; } else if (input.substr(0, 2) === '0x') { - return input.substr(2).toLowerCase().match(/.{1,2}/g).map((value) => parseInt(value, 16)); + const matches = input.substr(2).toLowerCase().match(/.{1,2}/g) || []; + return matches.map((value) => parseInt(value, 16)); } else { return input.split('').map((char) => char.charCodeAt(0)); } diff --git a/js/src/api/contract/contract.js b/js/src/api/contract/contract.js index 8d556a118..06afb0d9d 100644 --- a/js/src/api/contract/contract.js +++ b/js/src/api/contract/contract.js @@ -40,9 +40,12 @@ export default class Contract { this._events.forEach((evt) => { this._instance[evt.name] = evt; + this._instance[evt.signature] = evt; }); + this._functions.forEach((fn) => { this._instance[fn.name] = fn; + this._instance[fn.signature] = fn; }); this._sendSubscriptionChanges(); diff --git a/js/src/api/contract/contract.spec.js b/js/src/api/contract/contract.spec.js index 3d57c2afa..9c08024a9 100644 --- a/js/src/api/contract/contract.spec.js +++ b/js/src/api/contract/contract.spec.js @@ -20,6 +20,7 @@ import sinon from 'sinon'; import { TEST_HTTP_URL, mockHttp } from '../../../test/mockRpc'; import Abi from '../../abi'; +import { sha3 } from '../util/sha3'; import Api from '../api'; import Contract from './contract'; @@ -113,7 +114,13 @@ describe('api/contract/Contract', () => { ]); contract.at('6789'); - expect(Object.keys(contract.instance)).to.deep.equal(['Drained', 'balanceOf', 'address']); + expect(Object.keys(contract.instance)).to.deep.equal([ + 'Drained', + /^(?:0x)(.+)$/.exec(sha3('Drained(uint256)'))[1], + 'balanceOf', + /^(?:0x)(.+)$/.exec(sha3('balanceOf(address)'))[1].substr(0, 8), + 'address' + ]); expect(contract.address).to.equal('6789'); }); }); diff --git a/js/src/api/format/input.js b/js/src/api/format/input.js index 830ca0e21..4cd1c8a56 100644 --- a/js/src/api/format/input.js +++ b/js/src/api/format/input.js @@ -166,3 +166,11 @@ export function inTraceFilter (filterObject) { return filterObject; } + +export function inTraceType (whatTrace) { + if (isString(whatTrace)) { + return [whatTrace]; + } + + return whatTrace; +} diff --git a/js/src/api/format/input.spec.js b/js/src/api/format/input.spec.js index 219886d05..a22c8d131 100644 --- a/js/src/api/format/input.spec.js +++ b/js/src/api/format/input.spec.js @@ -16,7 +16,7 @@ import BigNumber from 'bignumber.js'; -import { inAddress, inBlockNumber, inData, inFilter, inHex, inNumber10, inNumber16, inOptions } from './input'; +import { inAddress, inBlockNumber, inData, inFilter, inHex, inNumber10, inNumber16, inOptions, inTraceType } from './input'; import { isAddress } from '../../../test/types'; describe('api/format/input', () => { @@ -242,4 +242,16 @@ describe('api/format/input', () => { }); }); }); + + describe('inTraceType', () => { + it('returns array of types as is', () => { + const types = ['vmTrace', 'trace', 'stateDiff']; + expect(inTraceType(types)).to.deep.equal(types); + }); + + it('formats single string type into array', () => { + const type = 'vmTrace'; + expect(inTraceType(type)).to.deep.equal([type]); + }); + }); }); diff --git a/js/src/api/format/output.js b/js/src/api/format/output.js index 8461df20f..262a275a0 100644 --- a/js/src/api/format/output.js +++ b/js/src/api/format/output.js @@ -254,3 +254,25 @@ export function outTrace (trace) { return trace; } + +export function outTraces (traces) { + if (traces) { + return traces.map(outTrace); + } + + return traces; +} + +export function outTraceReplay (trace) { + if (trace) { + Object.keys(trace).forEach((key) => { + switch (key) { + case 'trace': + trace[key] = outTraces(trace[key]); + break; + } + }); + } + + return trace; +} diff --git a/js/src/api/rpc/trace/trace.e2e.js b/js/src/api/rpc/trace/trace.e2e.js index 1a0720927..88c0988f6 100644 --- a/js/src/api/rpc/trace/trace.e2e.js +++ b/js/src/api/rpc/trace/trace.e2e.js @@ -20,15 +20,25 @@ describe('ethapi.trace', () => { const ethapi = createHttpApi(); describe('block', () => { - it('returns the latest block', () => { - return ethapi.trace.block().then((block) => { - expect(block).to.be.ok; + it('returns the latest block traces', () => { + return ethapi.trace.block().then((traces) => { + expect(traces).to.be.ok; }); }); - it('returns a specified block', () => { - return ethapi.trace.block('0x65432').then((block) => { - expect(block).to.be.ok; + it('returns traces for a specified block', () => { + return ethapi.trace.block('0x65432').then((traces) => { + expect(traces).to.be.ok; + }); + }); + }); + + describe('replayTransaction', () => { + it('returns traces for a specific transaction', () => { + return ethapi.eth.getBlockByNumber().then((latestBlock) => { + return ethapi.trace.replayTransaction(latestBlock.transactions[0]).then((traces) => { + expect(traces).to.be.ok; + }); }); }); }); diff --git a/js/src/api/rpc/trace/trace.js b/js/src/api/rpc/trace/trace.js index 95fed4230..5c693c0b5 100644 --- a/js/src/api/rpc/trace/trace.js +++ b/js/src/api/rpc/trace/trace.js @@ -14,35 +14,53 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { inBlockNumber, inHex, inNumber16, inTraceFilter } from '../../format/input'; -import { outTrace } from '../../format/output'; +import { inBlockNumber, inData, inHex, inNumber16, inOptions, inTraceFilter, inTraceType } from '../../format/input'; +import { outTraces, outTraceReplay } from '../../format/output'; export default class Trace { constructor (transport) { this._transport = transport; } + block (blockNumber = 'latest') { + return this._transport + .execute('trace_block', inBlockNumber(blockNumber)) + .then(outTraces); + } + + call (options, blockNumber = 'latest', whatTrace = ['trace']) { + return this._transport + .execute('trace_call', inOptions(options), inBlockNumber(blockNumber), inTraceType(whatTrace)) + .then(outTraceReplay); + } + filter (filterObj) { return this._transport .execute('trace_filter', inTraceFilter(filterObj)) - .then(traces => traces.map(trace => outTrace(trace))); + .then(outTraces); } get (txHash, position) { return this._transport .execute('trace_get', inHex(txHash), inNumber16(position)) - .then(trace => outTrace(trace)); + .then(outTraces); + } + + rawTransaction (data, whatTrace = ['trace']) { + return this._transport + .execute('trace_rawTransaction', inData(data), inTraceType(whatTrace)) + .then(outTraceReplay); + } + + replayTransaction (txHash, whatTrace = ['trace']) { + return this._transport + .execute('trace_replayTransaction', txHash, inTraceType(whatTrace)) + .then(outTraceReplay); } transaction (txHash) { return this._transport .execute('trace_transaction', inHex(txHash)) - .then(traces => traces.map(trace => outTrace(trace))); - } - - block (blockNumber = 'latest') { - return this._transport - .execute('trace_block', inBlockNumber(blockNumber)) - .then(traces => traces.map(trace => outTrace(trace))); + .then(outTraces); } } diff --git a/js/src/api/transport/error.js b/js/src/api/transport/error.js new file mode 100644 index 000000000..341839f69 --- /dev/null +++ b/js/src/api/transport/error.js @@ -0,0 +1,53 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import ExtendableError from 'es6-error'; + +export const ERROR_CODES = { + UNSUPPORTED_REQUEST: -32000, + NO_WORK: -32001, + NO_AUTHOR: -32002, + NO_NEW_WORK: -32003, + NOT_ENOUGH_DATA: -32006, + UNKNOWN_ERROR: -32009, + TRANSACTION_ERROR: -32010, + EXECUTION_ERROR: -32015, + ACCOUNT_LOCKED: -32020, + PASSWORD_INVALID: -32021, + ACCOUNT_ERROR: -32023, + SIGNER_DISABLED: -32030, + DAPPS_DISABLED: -32031, + NETWORK_DISABLED: -32035, + REQUEST_REJECTED: -32040, + REQUEST_REJECTED_LIMIT: -32041, + REQUEST_NOT_FOUND: -32042, + COMPILATION_ERROR: -32050, + ENCRYPTION_ERROR: -32055, + FETCH_ERROR: -32060 +}; + +export default class TransportError extends ExtendableError { + constructor (method, code, message) { + const m = `${method}: ${code}: ${message}`; + super(m); + + this.code = code; + this.type = Object.keys(ERROR_CODES).find((k) => ERROR_CODES[k] === code) || ''; + + this.method = method; + this.text = message; + } +} diff --git a/js/src/api/transport/http/http.js b/js/src/api/transport/http/http.js index 8ea59f0fb..591b9a627 100644 --- a/js/src/api/transport/http/http.js +++ b/js/src/api/transport/http/http.js @@ -16,6 +16,7 @@ import { Logging } from '../../subscriptions'; import JsonRpcBase from '../jsonRpcBase'; +import TransportError from '../error'; /* global fetch */ export default class Http extends JsonRpcBase { @@ -73,7 +74,8 @@ export default class Http extends JsonRpcBase { this.error(JSON.stringify(response)); console.error(`${method}(${JSON.stringify(params)}): ${response.error.code}: ${response.error.message}`); - throw new Error(`${method}: ${response.error.code}: ${response.error.message}`); + const error = new TransportError(method, response.error.code, response.error.message); + throw error; } this.log(JSON.stringify(response)); diff --git a/js/src/api/transport/index.js b/js/src/api/transport/index.js index 8f67fba4d..84fbac826 100644 --- a/js/src/api/transport/index.js +++ b/js/src/api/transport/index.js @@ -16,3 +16,4 @@ export Http from './http'; export Ws from './ws'; +export TransportError from './error.js'; diff --git a/js/src/api/transport/ws/ws.js b/js/src/api/transport/ws/ws.js index d608426b0..1cb1fb1c4 100644 --- a/js/src/api/transport/ws/ws.js +++ b/js/src/api/transport/ws/ws.js @@ -18,6 +18,7 @@ import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase import { Logging } from '../../subscriptions'; import JsonRpcBase from '../jsonRpcBase'; +import TransportError from '../error'; /* global WebSocket */ export default class Ws extends JsonRpcBase { @@ -109,7 +110,9 @@ export default class Ws extends JsonRpcBase { console.error(`${method}(${JSON.stringify(params)}): ${result.error.code}: ${result.error.message}`); - reject(new Error(`${method}: ${result.error.code}: ${result.error.message}`)); + const error = new TransportError(method, result.error.code, result.error.message); + reject(error); + delete this._messages[result.id]; return; } diff --git a/js/src/api/util/format.js b/js/src/api/util/format.js index 1b68e1138..198e456ee 100644 --- a/js/src/api/util/format.js +++ b/js/src/api/util/format.js @@ -17,3 +17,15 @@ export function bytesToHex (bytes) { return '0x' + bytes.map((b) => ('0' + b.toString(16)).slice(-2)).join(''); } + +export function hex2Ascii (_hex) { + const hex = /^(?:0x)?(.*)$/.exec(_hex.toString())[1]; + + let str = ''; + + for (let i = 0; i < hex.length; i += 2) { + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + + return str; +} diff --git a/js/src/api/util/index.js b/js/src/api/util/index.js index fb0f79076..55cf008c5 100644 --- a/js/src/api/util/index.js +++ b/js/src/api/util/index.js @@ -16,7 +16,7 @@ import { isAddress as isAddressValid, toChecksumAddress } from '../../abi/util/address'; import { decodeCallData, decodeMethodInput, methodToAbi } from './decode'; -import { bytesToHex } from './format'; +import { bytesToHex, hex2Ascii } from './format'; import { fromWei, toWei } from './wei'; import { sha3 } from './sha3'; import { isArray, isFunction, isHex, isInstanceOf, isString } from './types'; @@ -30,6 +30,7 @@ export default { isInstanceOf, isString, bytesToHex, + hex2Ascii, createIdentityImg, decodeCallData, decodeMethodInput, diff --git a/js/src/contracts/abi/index.js b/js/src/contracts/abi/index.js index 80f49dc5b..a6a7f0783 100644 --- a/js/src/contracts/abi/index.js +++ b/js/src/contracts/abi/index.js @@ -23,6 +23,7 @@ import githubhint from './githubhint.json'; import owned from './owned.json'; import registry from './registry.json'; import signaturereg from './signaturereg.json'; +import smsverification from './sms-verification.json'; import tokenreg from './tokenreg.json'; import wallet from './wallet.json'; @@ -36,6 +37,7 @@ export { owned, registry, signaturereg, + smsverification, tokenreg, wallet }; diff --git a/js/src/contracts/abi/sms-verification.json b/js/src/contracts/abi/sms-verification.json new file mode 100644 index 000000000..400d22b44 --- /dev/null +++ b/js/src/contracts/abi/sms-verification.json @@ -0,0 +1 @@ +[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] diff --git a/js/src/contracts/contracts.js b/js/src/contracts/contracts.js index c9d1c2390..9d745762c 100644 --- a/js/src/contracts/contracts.js +++ b/js/src/contracts/contracts.js @@ -18,6 +18,8 @@ import DappReg from './dappreg'; import Registry from './registry'; import SignatureReg from './signaturereg'; import TokenReg from './tokenreg'; +import GithubHint from './githubhint'; +import smsVerification from './sms-verification'; let instance = null; @@ -30,6 +32,7 @@ export default class Contracts { this._dappreg = new DappReg(api, this._registry); this._signaturereg = new SignatureReg(api, this._registry); this._tokenreg = new TokenReg(api, this._registry); + this._githubhint = new GithubHint(api, this._registry); } get registry () { @@ -48,6 +51,14 @@ export default class Contracts { return this._tokenreg; } + get githubHint () { + return this._githubhint; + } + + get smsVerification () { + return smsVerification; + } + static create (api) { return new Contracts(api); } diff --git a/js/src/contracts/githubhint.js b/js/src/contracts/githubhint.js new file mode 100644 index 000000000..47d7eca6e --- /dev/null +++ b/js/src/contracts/githubhint.js @@ -0,0 +1,32 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default class GithubHint { + constructor (api, registry) { + this._api = api; + this._registry = registry; + + this.getInstance(); + } + + getContract () { + return this._registry.getContract('githubhint'); + } + + getInstance () { + return this.getContract().instance; + } +} diff --git a/js/src/contracts/registry.js b/js/src/contracts/registry.js index 9853c0df9..d52b20718 100644 --- a/js/src/contracts/registry.js +++ b/js/src/contracts/registry.js @@ -42,7 +42,7 @@ export default class Registry { }); } - getContractInstance (_name) { + getContract (_name) { const name = _name.toLowerCase(); return new Promise((resolve, reject) => { @@ -54,13 +54,19 @@ export default class Registry { this .lookupAddress(name) .then((address) => { - this._contracts[name] = this._api.newContract(abis[name], address).instance; + this._contracts[name] = this._api.newContract(abis[name], address); resolve(this._contracts[name]); }) .catch(reject); }); } + getContractInstance (_name) { + return this + .getContract(_name) + .then((contract) => contract.instance); + } + lookupAddress (_name) { const name = _name.toLowerCase(); const sha3 = this._api.util.sha3(name); diff --git a/js/src/contracts/sms-verification.js b/js/src/contracts/sms-verification.js new file mode 100644 index 000000000..e93d57ffc --- /dev/null +++ b/js/src/contracts/sms-verification.js @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { stringify } from 'querystring'; + +export const checkIfVerified = (contract, account) => { + return contract.instance.certified.call({}, [account]); +}; + +export const checkIfRequested = (contract, account) => { + return new Promise((resolve, reject) => { + contract.subscribe('Requested', { + fromBlock: 0, toBlock: 'pending' + }, (err, logs) => { + if (err) { + return reject(err); + } + const e = logs.find((l) => { + return l.type === 'mined' && l.params.who && l.params.who.value === account; + }); + resolve(e ? e.transactionHash : false); + }); + }); +}; + +export const postToServer = (query) => { + query = stringify(query); + return fetch('https://sms-verification.parity.io/?' + query, { + method: 'POST', mode: 'cors', cache: 'no-store' + }) + .then((res) => { + return res.json().then((data) => { + if (res.ok) { + return data.message; + } + throw new Error(data.message || 'unknown error'); + }); + }); +}; diff --git a/js/src/contracts/tokenreg.js b/js/src/contracts/tokenreg.js index 78bd5e4d9..5e317880b 100644 --- a/js/src/contracts/tokenreg.js +++ b/js/src/contracts/tokenreg.js @@ -22,8 +22,12 @@ export default class TokenReg { this.getInstance(); } + getContract () { + return this._registry.getContract('tokenreg'); + } + getInstance () { - return this._registry.getContractInstance('tokenreg'); + return this.getContract().instance; } tokenCount () { diff --git a/js/src/dapps/basiccoin/AddressSelect/addressSelect.css b/js/src/dapps/basiccoin/AddressSelect/addressSelect.css index ddfd334e8..818906708 100644 --- a/js/src/dapps/basiccoin/AddressSelect/addressSelect.css +++ b/js/src/dapps/basiccoin/AddressSelect/addressSelect.css @@ -21,3 +21,7 @@ .iconMenu option { padding-left: 30px; } + +.menu { + display: none; +} diff --git a/js/src/dapps/basiccoin/Deploy/Event/event.css b/js/src/dapps/basiccoin/Deploy/Event/event.css index 52eada915..40768f6dc 100644 --- a/js/src/dapps/basiccoin/Deploy/Event/event.css +++ b/js/src/dapps/basiccoin/Deploy/Event/event.css @@ -46,11 +46,22 @@ a.link, a.link:hover, a.link:visited { } .address { + max-width: 250px; text-align: left; + + div { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } } .description { text-align: left; + + div { + white-space: nowrap; + } } .center { diff --git a/js/src/dapps/basiccoin/Deploy/Event/event.js b/js/src/dapps/basiccoin/Deploy/Event/event.js index 889822208..b32795f7e 100644 --- a/js/src/dapps/basiccoin/Deploy/Event/event.js +++ b/js/src/dapps/basiccoin/Deploy/Event/event.js @@ -58,6 +58,7 @@ export default class Event extends Component {
{ isPending ? '' : coin.tla }
{ isPending ? '' : coin.name }
+
{ this.renderAddress(event.params.coin) }
{ this.renderAddress(event.params.owner) } diff --git a/js/src/dapps/basiccoin/Overview/Owner/owner.css b/js/src/dapps/basiccoin/Overview/Owner/owner.css index 13e89d061..f94945722 100644 --- a/js/src/dapps/basiccoin/Overview/Owner/owner.css +++ b/js/src/dapps/basiccoin/Overview/Owner/owner.css @@ -46,3 +46,9 @@ .icon { margin: 0 0 -4px 1em; } + +.byline { + opacity: 0.75; + font-size: 0.75em; + padding-top: 0.25em; +} diff --git a/js/src/dapps/basiccoin/Overview/Owner/owner.js b/js/src/dapps/basiccoin/Overview/Owner/owner.js index cc3003693..a86a27544 100644 --- a/js/src/dapps/basiccoin/Overview/Owner/owner.js +++ b/js/src/dapps/basiccoin/Overview/Owner/owner.js @@ -68,6 +68,9 @@ export default class Owner extends Component { +
+ { token.address } +
)); } diff --git a/js/src/dapps/tokenreg/Accounts/actions.js b/js/src/dapps/tokenreg/Accounts/actions.js index a310baf7d..5f92280be 100644 --- a/js/src/dapps/tokenreg/Accounts/actions.js +++ b/js/src/dapps/tokenreg/Accounts/actions.js @@ -46,8 +46,6 @@ export const loadAccounts = () => (dispatch) => { address })); - console.log('accounts', accountsList); - dispatch(setAccounts(accountsList)); dispatch(setAccountsInfo(accountsInfo)); dispatch(setSelectedAccount(accountsList[0].address)); diff --git a/js/src/dapps/tokenreg/Actions/Query/query.js b/js/src/dapps/tokenreg/Actions/Query/query.js index 16d13f2f0..5a3c7d5f6 100644 --- a/js/src/dapps/tokenreg/Actions/Query/query.js +++ b/js/src/dapps/tokenreg/Actions/Query/query.js @@ -42,12 +42,9 @@ export default class QueryAction extends Component { onClose: PropTypes.func.isRequired, handleQueryToken: PropTypes.func.isRequired, - handleQueryMetaLookup: PropTypes.func.isRequired, data: PropTypes.object, - notFound: PropTypes.bool, - metaLoading: PropTypes.bool, - metaData: PropTypes.object + notFound: PropTypes.bool } state = initState; @@ -131,11 +128,8 @@ export default class QueryAction extends Component { return ( + tla={ data.tla } + /> ); } diff --git a/js/src/dapps/tokenreg/Actions/Register/register.js b/js/src/dapps/tokenreg/Actions/Register/register.js index 8ae042494..a008ce84f 100644 --- a/js/src/dapps/tokenreg/Actions/Register/register.js +++ b/js/src/dapps/tokenreg/Actions/Register/register.js @@ -21,7 +21,7 @@ import { Dialog, FlatButton } from 'material-ui'; import AccountSelector from '../../Accounts/AccountSelector'; import InputText from '../../Inputs/Text'; -import { TOKEN_ADDRESS_TYPE, TLA_TYPE, UINT_TYPE, STRING_TYPE } from '../../Inputs/validation'; +import { TOKEN_ADDRESS_TYPE, TLA_TYPE, DECIMAL_TYPE, STRING_TYPE } from '../../Inputs/validation'; import styles from '../actions.css'; @@ -41,11 +41,11 @@ const initState = { floatingLabelText: 'Token TLA', hintText: 'The token short name (3 characters)' }, - base: { + decimals: { ...defaultField, - type: UINT_TYPE, - floatingLabelText: 'Token Base', - hintText: 'The token precision' + type: DECIMAL_TYPE, + floatingLabelText: 'Token Decimals', + hintText: 'The number of decimals (0-18)' }, name: { ...defaultField, diff --git a/js/src/dapps/tokenreg/Actions/actions.js b/js/src/dapps/tokenreg/Actions/actions.js index 0f3390ea4..df5b41e6b 100644 --- a/js/src/dapps/tokenreg/Actions/actions.js +++ b/js/src/dapps/tokenreg/Actions/actions.js @@ -16,8 +16,6 @@ import { getTokenTotalSupply } from '../utils'; -const { sha3, bytesToHex } = window.parity.api.util; - export const SET_REGISTER_SENDING = 'SET_REGISTER_SENDING'; export const setRegisterSending = (isSending) => ({ type: SET_REGISTER_SENDING, @@ -41,13 +39,12 @@ export const registerCompleted = () => ({ }); export const registerToken = (tokenData) => (dispatch, getState) => { - console.log('registering token', tokenData); - const state = getState(); const contractInstance = state.status.contract.instance; const fee = state.status.contract.fee; - const { address, base, name, tla } = tokenData; + const { address, decimals, name, tla } = tokenData; + const base = Math.pow(10, decimals); dispatch(setRegisterSending(true)); @@ -82,8 +79,6 @@ export const registerToken = (tokenData) => (dispatch, getState) => { }) .then((gasEstimate) => { options.gas = gasEstimate.mul(1.2).toFixed(0); - console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`); - return contractInstance.register.postTransaction(options, values); }) .then((result) => { @@ -182,34 +177,3 @@ export const queryToken = (key, query) => (dispatch, getState) => { dispatch(setQueryLoading(false)); }); }; - -export const queryTokenMeta = (id, query) => (dispatch, getState) => { - console.log('loading token meta', query); - - const state = getState(); - const contractInstance = state.status.contract.instance; - - const key = sha3(query); - - const startDate = Date.now(); - dispatch(setQueryMetaLoading(true)); - - contractInstance - .meta - .call({}, [ id, key ]) - .then((value) => { - const meta = { - key, query, - value: value.find(v => v !== 0) ? bytesToHex(value) : null - }; - - dispatch(setQueryMeta(meta)); - - setTimeout(() => { - dispatch(setQueryMetaLoading(false)); - }, 500 - (Date.now() - startDate)); - }) - .catch((e) => { - console.error('load meta query error', e); - }); -}; diff --git a/js/src/dapps/tokenreg/Actions/component.js b/js/src/dapps/tokenreg/Actions/component.js index 3e7ef0d64..43acc27ab 100644 --- a/js/src/dapps/tokenreg/Actions/component.js +++ b/js/src/dapps/tokenreg/Actions/component.js @@ -37,7 +37,6 @@ export default class Actions extends Component { handleQueryToken: PropTypes.func.isRequired, handleQueryClose: PropTypes.func.isRequired, - handleQueryMetaLookup: PropTypes.func.isRequired, query: PropTypes.object.isRequired }; @@ -82,7 +81,6 @@ export default class Actions extends Component { show={ this.state.show[ QUERY_ACTION ] } onClose={ this.onQueryClose } handleQueryToken={ this.props.handleQueryToken } - handleQueryMetaLookup={ this.props.handleQueryMetaLookup } { ...this.props.query } /> ); diff --git a/js/src/dapps/tokenreg/Actions/container.js b/js/src/dapps/tokenreg/Actions/container.js index 2c3773122..1d3d8fe31 100644 --- a/js/src/dapps/tokenreg/Actions/container.js +++ b/js/src/dapps/tokenreg/Actions/container.js @@ -19,7 +19,7 @@ import { connect } from 'react-redux'; import Actions from './component'; -import { registerToken, registerReset, queryToken, queryReset, queryTokenMeta } from './actions'; +import { registerToken, registerReset, queryToken, queryReset } from './actions'; class TokensContainer extends Component { @@ -49,9 +49,6 @@ const mapDispatchToProps = (dispatch) => { }, handleQueryClose: () => { dispatch(queryReset()); - }, - handleQueryMetaLookup: (id, query) => { - dispatch(queryTokenMeta(id, query)); } }; }; diff --git a/js/src/dapps/tokenreg/Application/application.css b/js/src/dapps/tokenreg/Application/application.css index 033147ae3..94ca6302e 100644 --- a/js/src/dapps/tokenreg/Application/application.css +++ b/js/src/dapps/tokenreg/Application/application.css @@ -19,6 +19,7 @@ display: flex; flex-direction: column; align-items: center; + padding-bottom: 10em; } .warning { diff --git a/js/src/dapps/tokenreg/Inputs/validation.js b/js/src/dapps/tokenreg/Inputs/validation.js index 38eba5ef1..fd394b4ec 100644 --- a/js/src/dapps/tokenreg/Inputs/validation.js +++ b/js/src/dapps/tokenreg/Inputs/validation.js @@ -32,6 +32,7 @@ export const SIMPLE_TOKEN_ADDRESS_TYPE = 'SIMPLE_TOKEN_ADDRESS_TYPE'; export const TLA_TYPE = 'TLA_TYPE'; export const SIMPLE_TLA_TYPE = 'SIMPLE_TLA_TYPE'; export const UINT_TYPE = 'UINT_TYPE'; +export const DECIMAL_TYPE = 'DECIMAL_TYPE'; export const STRING_TYPE = 'STRING_TYPE'; export const HEX_TYPE = 'HEX_TYPE'; export const URL_TYPE = 'URL_TYPE'; @@ -39,6 +40,7 @@ export const URL_TYPE = 'URL_TYPE'; export const ERRORS = { invalidTLA: 'The TLA should be 3 characters long', invalidUint: 'Please enter a non-negative integer', + invalidDecimal: 'Please enter a value between 0 and 18', invalidString: 'Please enter at least a character', invalidAccount: 'Please select an account to transact with', invalidRecipient: 'Please select an account to send to', @@ -152,6 +154,21 @@ const validateUint = (uint) => { }; }; +const validateDecimal = (decimal) => { + if (!/^\d+$/.test(decimal) || parseInt(decimal) < 0 || parseInt(decimal) > 18) { + return { + error: ERRORS.invalidDecimal, + valid: false + }; + } + + return { + value: parseInt(decimal), + error: null, + valid: true + }; +}; + const validateString = (string) => { if (string.toString().length === 0) { return { @@ -204,6 +221,7 @@ export const validate = (value, type, contract) => { if (type === TLA_TYPE) return validateTLA(value, contract); if (type === SIMPLE_TLA_TYPE) return validateTLA(value, contract, true); if (type === UINT_TYPE) return validateUint(value); + if (type === DECIMAL_TYPE) return validateDecimal(value); if (type === STRING_TYPE) return validateString(value); if (type === HEX_TYPE) return validateHex(value); if (type === URL_TYPE) return validateURL(value); diff --git a/js/src/dapps/tokenreg/Status/actions.js b/js/src/dapps/tokenreg/Status/actions.js index e9e217d6a..b07949a28 100644 --- a/js/src/dapps/tokenreg/Status/actions.js +++ b/js/src/dapps/tokenreg/Status/actions.js @@ -14,11 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { - registry as registryAbi, - tokenreg as tokenregAbi, - githubhint as githubhintAbi -} from '../../../contracts/abi'; +import Contracts from '../../../contracts'; import { loadToken, setTokenPending, deleteToken, setTokenData } from '../Tokens/actions'; @@ -34,43 +30,31 @@ export const FIND_CONTRACT = 'FIND_CONTRACT'; export const loadContract = () => (dispatch) => { dispatch(setLoading(true)); - api.parity - .registryAddress() - .then((registryAddress) => { - console.log(`registry found at ${registryAddress}`); - const registry = api.newContract(registryAbi, registryAddress).instance; - - return Promise.all([ - registry.getAddress.call({}, [api.util.sha3('tokenreg'), 'A']), - registry.getAddress.call({}, [api.util.sha3('githubhint'), 'A']) - ]); - }) - .then(([ tokenregAddress, githubhintAddress ]) => { - console.log(`tokenreg was found at ${tokenregAddress}`); - - const tokenregContract = api - .newContract(tokenregAbi, tokenregAddress); - - const githubhintContract = api - .newContract(githubhintAbi, githubhintAddress); + const { tokenReg, githubHint } = new Contracts(api); + return Promise + .all([ + tokenReg.getContract(), + githubHint.getContract() + ]) + .then(([ tokenRegContract, githubHintContract ]) => { dispatch(setContractDetails({ - address: tokenregAddress, - instance: tokenregContract.instance, - raw: tokenregContract + address: tokenRegContract.address, + instance: tokenRegContract.instance, + raw: tokenRegContract })); dispatch(setGithubhintDetails({ - address: githubhintAddress, - instance: githubhintContract.instance, - raw: githubhintContract + address: githubHintContract.address, + instance: githubHintContract.instance, + raw: githubHintContract })); dispatch(loadContractDetails()); dispatch(subscribeEvents()); }) .catch((error) => { - console.error('loadContract error', error); + throw error; }); }; @@ -78,7 +62,7 @@ export const LOAD_CONTRACT_DETAILS = 'LOAD_CONTRACT_DETAILS'; export const loadContractDetails = () => (dispatch, getState) => { const state = getState(); - const instance = state.status.contract.instance; + const { instance } = state.status.contract; Promise .all([ @@ -87,8 +71,6 @@ export const loadContractDetails = () => (dispatch, getState) => { instance.fee.call() ]) .then(([accounts, owner, fee]) => { - console.log(`owner as ${owner}, fee set at ${fee.toFormat()}`); - const isOwner = accounts.filter(a => a === owner).length > 0; dispatch(setContractDetails({ @@ -119,14 +101,14 @@ export const setGithubhintDetails = (details) => ({ export const subscribeEvents = () => (dispatch, getState) => { const state = getState(); - const contract = state.status.contract.raw; + const { raw } = state.status.contract; const previousSubscriptionId = state.status.subscriptionId; if (previousSubscriptionId) { - contract.unsubscribe(previousSubscriptionId); + raw.unsubscribe(previousSubscriptionId); } - contract + raw .subscribe(null, { fromBlock: 'latest', toBlock: 'pending', @@ -187,7 +169,7 @@ export const subscribeEvents = () => (dispatch, getState) => { )); } - console.log('new log event', log); + console.warn('unknown log event', log); }); }) .then((subscriptionId) => { diff --git a/js/src/dapps/tokenreg/Status/reducer.js b/js/src/dapps/tokenreg/Status/reducer.js index 7b018bd85..aee16fbe7 100644 --- a/js/src/dapps/tokenreg/Status/reducer.js +++ b/js/src/dapps/tokenreg/Status/reducer.js @@ -25,17 +25,15 @@ const initialState = { isLoading: true, subscriptionId: null, contract: { - addres: null, + address: null, instance: null, - raw: null, owner: null, isOwner: false, fee: null }, githubhint: { address: null, - instance: null, - raw: null + instance: null } }; diff --git a/js/src/dapps/tokenreg/Tokens/Token/index.js b/js/src/dapps/tokenreg/Tokens/Token/index.js index 4b822b4bd..30ad8896f 100644 --- a/js/src/dapps/tokenreg/Tokens/Token/index.js +++ b/js/src/dapps/tokenreg/Tokens/Token/index.js @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -export default from './token'; +export default from './tokenContainer'; diff --git a/js/src/dapps/tokenreg/Tokens/Token/token.js b/js/src/dapps/tokenreg/Tokens/Token/token.js index 34550ef48..be14cec84 100644 --- a/js/src/dapps/tokenreg/Tokens/Token/token.js +++ b/js/src/dapps/tokenreg/Tokens/Token/token.js @@ -57,15 +57,28 @@ export default class Token extends Component { isLoading: PropTypes.bool, isPending: PropTypes.bool, isTokenOwner: PropTypes.bool.isRequired, - isContractOwner: PropTypes.bool.isRequired, + isContractOwner: PropTypes.bool, fullWidth: PropTypes.bool }; - state = { - metaKeyIndex: 0 + static defaultProps = { + isContractOwner: false }; + state = { + metaKeyIndex: 0, + showMeta: false + }; + + shouldComponentUpdate (nextProps) { + if (nextProps.isLoading && this.props.isLoading) { + return false; + } + + return true; + } + render () { const { isLoading, fullWidth } = this.props; @@ -152,8 +165,8 @@ export default class Token extends Component { if (!base || base < 0) return null; return ( + value={ Math.log10(base).toString() } + label='Decimals' /> ); } @@ -237,7 +250,12 @@ export default class Token extends Component { } renderMeta (meta) { - const isMetaLoading = this.props.isMetaLoading; + const { isMetaLoading } = this.props; + const { showMeta } = this.state; + + if (!showMeta) { + return null; + } if (isMetaLoading) { return (
@@ -331,6 +349,7 @@ export default class Token extends Component { const key = metaDataKeys[keyIndex].value; const index = this.props.index; + this.setState({ showMeta: true }); this.props.handleMetaLookup(index, key); } diff --git a/js/src/dapps/tokenreg/Tokens/Token/tokenContainer.js b/js/src/dapps/tokenreg/Tokens/Token/tokenContainer.js new file mode 100644 index 000000000..7351da524 --- /dev/null +++ b/js/src/dapps/tokenreg/Tokens/Token/tokenContainer.js @@ -0,0 +1,73 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; + +import Token from './token'; + +import { queryTokenMeta, unregisterToken, addTokenMeta } from '../actions'; + +class TokenContainer extends Component { + static propTypes = { + handleMetaLookup: PropTypes.func.isRequired, + handleUnregister: PropTypes.func.isRequired, + handleAddMeta: PropTypes.func.isRequired, + + tla: PropTypes.string.isRequired + }; + + render () { + return ( + + ); + } +} + +const mapStateToProps = (_, initProps) => { + const { tla } = initProps; + + return (state) => { + const { isOwner } = state.status.contract; + const { tokens } = state.tokens; + const token = tokens.find((t) => t.tla === tla); + + return { ...token, isContractOwner: isOwner }; + }; +}; + +const mapDispatchToProps = (dispatch) => { + return { + handleMetaLookup: (index, query) => { + dispatch(queryTokenMeta(index, query)); + }, + + handleUnregister: (index) => { + dispatch(unregisterToken(index)); + }, + + handleAddMeta: (index, key, value) => { + dispatch(addTokenMeta(index, key, value)); + } + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(TokenContainer); diff --git a/js/src/dapps/tokenreg/Tokens/actions.js b/js/src/dapps/tokenreg/Tokens/actions.js index 7953bb241..d1e13c1dc 100644 --- a/js/src/dapps/tokenreg/Tokens/actions.js +++ b/js/src/dapps/tokenreg/Tokens/actions.js @@ -67,8 +67,6 @@ export const deleteToken = (index) => ({ }); export const loadTokens = () => (dispatch, getState) => { - console.log('loading tokens...'); - const state = getState(); const contractInstance = state.status.contract.instance; @@ -79,7 +77,6 @@ export const loadTokens = () => (dispatch, getState) => { .call() .then((count) => { const tokenCount = parseInt(count); - console.log(`token count: ${tokenCount}`); dispatch(setTokenCount(tokenCount)); for (let i = 0; i < tokenCount; i++) { @@ -94,8 +91,6 @@ export const loadTokens = () => (dispatch, getState) => { }; export const loadToken = (index) => (dispatch, getState) => { - console.log('loading token', index); - const state = getState(); const contractInstance = state.status.contract.instance; @@ -144,7 +139,7 @@ export const loadToken = (index) => (dispatch, getState) => { } data.totalSupply = data.totalSupply.toNumber(); - console.log(`token loaded: #${index}`, data); + dispatch(setTokenData(index, data)); dispatch(setTokenLoading(index, false)); }) @@ -159,8 +154,6 @@ export const loadToken = (index) => (dispatch, getState) => { }; export const queryTokenMeta = (index, query) => (dispatch, getState) => { - console.log('loading token meta', index, query); - const state = getState(); const contractInstance = state.status.contract.instance; @@ -176,7 +169,6 @@ export const queryTokenMeta = (index, query) => (dispatch, getState) => { value: value.find(v => v !== 0) ? bytesToHex(value) : null }; - console.log(`token meta loaded: #${index}`, value); dispatch(setTokenMeta(index, meta)); setTimeout(() => { @@ -189,8 +181,6 @@ export const queryTokenMeta = (index, query) => (dispatch, getState) => { }; export const addTokenMeta = (index, key, value) => (dispatch, getState) => { - console.log('add token meta', index, key, value); - const state = getState(); const contractInstance = state.status.contract.instance; const token = state.tokens.tokens.find(t => t.index === index); @@ -203,8 +193,6 @@ export const addTokenMeta = (index, key, value) => (dispatch, getState) => { .estimateGas(options, values) .then((gasEstimate) => { options.gas = gasEstimate.mul(1.2).toFixed(0); - console.log(`addTokenMeta: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`); - return contractInstance.setMeta.postTransaction(options, values); }) .catch((e) => { @@ -213,8 +201,6 @@ export const addTokenMeta = (index, key, value) => (dispatch, getState) => { }; export const addGithubhintURL = (from, key, url) => (dispatch, getState) => { - console.log('add githubhint url', key, url); - const state = getState(); const contractInstance = state.status.githubhint.instance; @@ -227,8 +213,6 @@ export const addGithubhintURL = (from, key, url) => (dispatch, getState) => { .estimateGas(options, values) .then((gasEstimate) => { options.gas = gasEstimate.mul(1.2).toFixed(0); - console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`); - return contractInstance.hintURL.postTransaction(options, values); }) .catch((e) => { @@ -237,24 +221,20 @@ export const addGithubhintURL = (from, key, url) => (dispatch, getState) => { }; export const unregisterToken = (index) => (dispatch, getState) => { - console.log('unregistering token', index); - - const state = getState(); - const contractInstance = state.status.contract.instance; + const { contract } = getState().status; + const { instance, owner } = contract; const values = [ index ]; const options = { - from: state.accounts.selected.address + from: owner }; - contractInstance + instance .unregister .estimateGas(options, values) .then((gasEstimate) => { options.gas = gasEstimate.mul(1.2).toFixed(0); - console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`); - - return contractInstance.unregister.postTransaction(options, values); + return instance.unregister.postTransaction(options, values); }) .catch((e) => { console.error(`unregisterToken #${index} error`, e); diff --git a/js/src/dapps/tokenreg/Tokens/container.js b/js/src/dapps/tokenreg/Tokens/container.js index b6171c2cc..33b2de659 100644 --- a/js/src/dapps/tokenreg/Tokens/container.js +++ b/js/src/dapps/tokenreg/Tokens/container.js @@ -19,16 +19,13 @@ import { connect } from 'react-redux'; import Tokens from './tokens'; -import { loadTokens, queryTokenMeta, unregisterToken, addTokenMeta } from './actions'; +import { loadTokens } from './actions'; class TokensContainer extends Component { static propTypes = { - isOwner: PropTypes.bool, isLoading: PropTypes.bool, tokens: PropTypes.array, - tokenCount: PropTypes.number, - onLoadTokens: PropTypes.func, - accounts: PropTypes.array + onLoadTokens: PropTypes.func }; componentDidMount () { @@ -36,7 +33,6 @@ class TokensContainer extends Component { } render () { - console.log(this.props); return ( { - const { list } = state.accounts; - const { isLoading, tokens, tokenCount } = state.tokens; + const { isLoading, tokens } = state.tokens; - const { isOwner } = state.status.contract; + const filteredTokens = tokens + .filter((token) => token && token.tla) + .map((token) => ({ tla: token.tla, owner: token.owner })); - return { isLoading, tokens, tokenCount, isOwner, accounts: list }; + return { isLoading, tokens: filteredTokens }; }; const mapDispatchToProps = (dispatch) => { return { onLoadTokens: () => { dispatch(loadTokens()); - }, - - handleMetaLookup: (index, query) => { - dispatch(queryTokenMeta(index, query)); - }, - - handleUnregister: (index) => { - dispatch(unregisterToken(index)); - }, - - handleAddMeta: (index, key, value) => { - dispatch(addTokenMeta(index, key, value)); } }; }; diff --git a/js/src/dapps/tokenreg/Tokens/tokens.js b/js/src/dapps/tokenreg/Tokens/tokens.js index 43766a8a8..48bc88a74 100644 --- a/js/src/dapps/tokenreg/Tokens/tokens.js +++ b/js/src/dapps/tokenreg/Tokens/tokens.js @@ -23,13 +23,8 @@ import styles from './tokens.css'; export default class Tokens extends Component { static propTypes = { - handleAddMeta: PropTypes.func.isRequired, - handleUnregister: PropTypes.func.isRequired, - handleMetaLookup: PropTypes.func.isRequired, - isOwner: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired, - tokens: PropTypes.array, - accounts: PropTypes.array + tokens: PropTypes.array }; render () { @@ -45,24 +40,12 @@ export default class Tokens extends Component { } renderTokens (tokens) { - const { accounts, isOwner } = this.props; - - return tokens.map((token, index) => { - if (!token || !token.tla) { - return null; - } - - const isTokenOwner = !!accounts.find((account) => account.address === token.owner); - + return tokens.map((token) => { return ( + key={ token.tla } + tla={ token.tla } + /> ); }); } diff --git a/js/src/index.js b/js/src/index.js index c0f4f94ad..fda785842 100644 --- a/js/src/index.js +++ b/js/src/index.js @@ -25,6 +25,7 @@ import ReactDOM from 'react-dom'; import injectTapEventPlugin from 'react-tap-event-plugin'; import { createHashHistory } from 'history'; import { Redirect, Router, Route, useRouterHistory } from 'react-router'; +import qs from 'querystring'; import SecureApi from './secureApi'; import ContractInstances from './contracts'; @@ -45,6 +46,7 @@ import './index.html'; injectTapEventPlugin(); +const AUTH_HASH = '#/auth?'; const parityUrl = process.env.PARITY_URL || ( process.env.NODE_ENV === 'production' @@ -52,7 +54,12 @@ const parityUrl = process.env.PARITY_URL || : '127.0.0.1:8180' ); -const api = new SecureApi(`ws://${parityUrl}`); +let token = null; +if (window.location.hash && window.location.hash.indexOf(AUTH_HASH) === 0) { + token = qs.parse(window.location.hash.substr(AUTH_HASH.length)).token; +} + +const api = new SecureApi(`ws://${parityUrl}`, token); ContractInstances.create(api); const store = initStore(api); @@ -67,6 +74,7 @@ ReactDOM.render( + diff --git a/js/src/jsonrpc/interfaces/trace.js b/js/src/jsonrpc/interfaces/trace.js index 3dc4451f0..efe45f34e 100644 --- a/js/src/jsonrpc/interfaces/trace.js +++ b/js/src/jsonrpc/interfaces/trace.js @@ -14,9 +14,45 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { BlockNumber, Hash, Integer } from '../types'; +import { BlockNumber, Data, Hash, Integer } from '../types'; export default { + block: { + desc: 'Returns traces created at given block', + params: [ + { + type: BlockNumber, + desc: 'Integer block number, or \'latest\' for the last mined block or \'pending\', \'earliest\' for not yet mined transactions' + } + ], + returns: { + type: Array, + desc: 'Block traces' + } + }, + + call: { + desc: 'Returns traces for a specific call', + params: [ + { + type: Object, + desc: 'Call options' + }, + { + type: BlockNumber, + desc: 'The blockNumber' + }, + { + type: Array, + desc: 'Type of trace, one or more of \'vmTrace\', \'trace\' and/or \'stateDiff\'' + } + ], + returns: { + type: Array, + desc: 'Block traces' + } + }, + filter: { desc: 'Returns traces matching given filter', params: [ @@ -49,6 +85,42 @@ export default { } }, + rawTransaction: { + desc: 'Traces a call to eth_sendRawTransaction without making the call, returning the traces', + params: [ + { + type: Data, + desc: 'Transaction data' + }, + { + type: Array, + desc: 'Type of trace, one or more of \'vmTrace\', \'trace\' and/or \'stateDiff\'' + } + ], + returns: { + type: Array, + desc: 'Block traces' + } + }, + + replayTransaction: { + desc: 'Replays a transaction, returning the traces', + params: [ + { + type: Hash, + desc: 'Transaction hash' + }, + { + type: Array, + desc: 'Type of trace, one or more of \'vmTrace\', \'trace\' and/or \'stateDiff\'' + } + ], + returns: { + type: Array, + desc: 'Block traces' + } + }, + transaction: { desc: 'Returns all traces of given transaction', params: [ @@ -61,19 +133,5 @@ export default { type: Array, desc: 'Traces of given transaction' } - }, - - block: { - desc: 'Returns traces created at given block', - params: [ - { - type: BlockNumber, - desc: 'Integer block number, or \'latest\' for the last mined block or \'pending\', \'earliest\' for not yet mined transactions' - } - ], - returns: { - type: Array, - desc: 'Block traces' - } } }; diff --git a/js/src/modals/AddContract/addContract.js b/js/src/modals/AddContract/addContract.js index 57773d2dc..4c73d3da0 100644 --- a/js/src/modals/AddContract/addContract.js +++ b/js/src/modals/AddContract/addContract.js @@ -227,6 +227,7 @@ export default class AddContract extends Component { onEditAbi = (abiIn) => { const { api } = this.context; const { abi, abiError, abiParsed } = validateAbi(abiIn, api); + this.setState({ abi, abiError, abiParsed }); } diff --git a/js/src/modals/DeployContract/DetailsStep/detailsStep.js b/js/src/modals/DeployContract/DetailsStep/detailsStep.js index 854715396..6e23f79c9 100644 --- a/js/src/modals/DeployContract/DetailsStep/detailsStep.js +++ b/js/src/modals/DeployContract/DetailsStep/detailsStep.js @@ -15,10 +15,10 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; -import { MenuItem } from 'material-ui'; -import { AddressSelect, Form, Input, InputAddressSelect, Select } from '../../../ui'; +import { AddressSelect, Form, Input, TypedInput } from '../../../ui'; import { validateAbi } from '../../../util/validation'; +import { parseAbiType } from '../../../util/abi'; import styles from '../deployContract.css'; @@ -103,6 +103,7 @@ export default class DetailsStep extends Component { value={ code } onSubmit={ this.onCodeChange } readOnly={ readOnly } /> + { this.renderConstructorInputs() } ); @@ -117,59 +118,23 @@ export default class DetailsStep extends Component { } return inputs.map((input, index) => { - const onChange = (event, value) => this.onParamChange(index, value); - const onChangeBool = (event, _index, value) => this.onParamChange(index, value === 'true'); - const onSubmit = (value) => this.onParamChange(index, value); - const label = `${input.name}: ${input.type}`; - let inputBox = null; + const onChange = (value) => this.onParamChange(index, value); - switch (input.type) { - case 'address': - inputBox = ( - - ); - break; - - case 'bool': - const boolitems = ['false', 'true'].map((bool) => { - return ( - { bool } - ); - }); - inputBox = ( - - ); - break; - - default: - inputBox = ( - - ); - break; - } + const label = `${input.name ? `${input.name}: ` : ''}${input.type}`; + const value = params[index]; + const error = paramsError[index]; + const param = parseAbiType(input.type); return (
- { inputBox } +
); }); @@ -200,35 +165,14 @@ export default class DetailsStep extends Component { const { abiError, abiParsed } = validateAbi(abi, api); if (!abiError) { - const { inputs } = abiParsed.find((method) => method.type === 'constructor') || { inputs: [] }; + const { inputs } = abiParsed + .find((method) => method.type === 'constructor') || { inputs: [] }; + const params = []; inputs.forEach((input) => { - switch (input.type) { - case 'address': - params.push('0x'); - break; - - case 'bool': - params.push(false); - break; - - case 'bytes': - params.push('0x'); - break; - - case 'uint': - params.push('0'); - break; - - case 'string': - params.push(''); - break; - - default: - params.push('0'); - break; - } + const param = parseAbiType(input.type); + params.push(param.default); }); onParamsChange(params); diff --git a/js/src/modals/DeployContract/deployContract.js b/js/src/modals/DeployContract/deployContract.js index 768723d1f..996948092 100644 --- a/js/src/modals/DeployContract/deployContract.js +++ b/js/src/modals/DeployContract/deployContract.js @@ -26,6 +26,8 @@ import ErrorStep from './ErrorStep'; import styles from './deployContract.css'; +import { ERROR_CODES } from '../../api/transport/error'; + const steps = ['contract details', 'deployment', 'completed']; export default class DeployContract extends Component { @@ -63,7 +65,8 @@ export default class DeployContract extends Component { params: [], paramsError: [], step: 0, - deployError: null + deployError: null, + rejected: false } componentWillMount () { @@ -92,16 +95,22 @@ export default class DeployContract extends Component { } render () { - const { step, deployError } = this.state; + const { step, deployError, rejected } = this.state; + + const realSteps = deployError || rejected ? null : steps; + const title = realSteps + ? null + : (deployError ? 'deployment failed' : 'rejected'); return ( + steps={ realSteps } + title={ title } + waiting={ realSteps ? [1] : null } + visible + scroll> { this.renderStep() } ); @@ -118,8 +127,22 @@ export default class DeployContract extends Component { onClick={ this.onClose } /> ); + const closeBtn = ( +
+ ); + } + + let action = () => {}; + switch (phase) { + case 1: + action = store.sendRequest; + break; + case 2: + action = store.queryCode; + break; + case 3: + action = store.sendConfirmation; + break; + case 4: + action = store.done; + break; + } + + return ( +
+ { cancel } +
+ ); + } + + renderStep (phase, error) { + if (error) { + return (

{ error }

); + } + + const { + step, + fee, number, isNumberValid, isVerified, hasRequested, + requestTx, isCodeValid, confirmationTx, + setNumber, setConsentGiven, setCode + } = this.props.store; + + if (phase === 5) { + return (); + } + if (phase === 4) { + return (); + } + if (phase === 3) { + return ( + + ); + } + if (phase === 2) { + return (); + } + if (phase === 1) { + const { setNumber, setConsentGiven } = this.props.store; + return ( + + ); + } + if (phase === 0) { + return (

Preparing awesomeness!

); + } + + return null; + } +} diff --git a/js/src/modals/SMSVerification/SendConfirmation/index.js b/js/src/modals/SMSVerification/SendConfirmation/index.js new file mode 100644 index 000000000..498a8572e --- /dev/null +++ b/js/src/modals/SMSVerification/SendConfirmation/index.js @@ -0,0 +1,17 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './sendConfirmation'; diff --git a/js/src/modals/SMSVerification/SendConfirmation/sendConfirmation.css b/js/src/modals/SMSVerification/SendConfirmation/sendConfirmation.css new file mode 100644 index 000000000..d2395f24d --- /dev/null +++ b/js/src/modals/SMSVerification/SendConfirmation/sendConfirmation.css @@ -0,0 +1,20 @@ +/* Copyright 2015, 2016 Ethcore (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.centered { + text-align: center; +} diff --git a/js/src/modals/SMSVerification/SendConfirmation/sendConfirmation.js b/js/src/modals/SMSVerification/SendConfirmation/sendConfirmation.js new file mode 100644 index 000000000..a3c8e3e18 --- /dev/null +++ b/js/src/modals/SMSVerification/SendConfirmation/sendConfirmation.js @@ -0,0 +1,51 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; +import nullable from '../../../util/nullable-proptype'; + +import TxHash from '../../../ui/TxHash'; +import { + POSTING_CONFIRMATION, POSTED_CONFIRMATION +} from '../store'; + +import styles from './sendConfirmation.css'; + +export default class SendConfirmation extends Component { + static propTypes = { + step: PropTypes.any.isRequired, + tx: nullable(PropTypes.any.isRequired) + } + + render () { + const { step, tx } = this.props; + + if (step === POSTING_CONFIRMATION) { + return (

The verification code will be sent to the contract. Please authorize this using the Parity Signer.

); + } + + if (step === POSTED_CONFIRMATION) { + return ( +
+ +

Please keep this window open.

+
+ ); + } + + return null; + } +} diff --git a/js/src/modals/SMSVerification/SendRequest/index.js b/js/src/modals/SMSVerification/SendRequest/index.js new file mode 100644 index 000000000..1a8bfaf73 --- /dev/null +++ b/js/src/modals/SMSVerification/SendRequest/index.js @@ -0,0 +1,17 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './sendRequest'; diff --git a/js/src/modals/SMSVerification/SendRequest/sendRequest.css b/js/src/modals/SMSVerification/SendRequest/sendRequest.css new file mode 100644 index 000000000..d2395f24d --- /dev/null +++ b/js/src/modals/SMSVerification/SendRequest/sendRequest.css @@ -0,0 +1,20 @@ +/* Copyright 2015, 2016 Ethcore (UK) Ltd. +/* This file is part of Parity. +/* +/* Parity is free software: you can redistribute it and/or modify +/* it under the terms of the GNU General Public License as published by +/* the Free Software Foundation, either version 3 of the License, or +/* (at your option) any later version. +/* +/* Parity is distributed in the hope that it will be useful, +/* but WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU General Public License for more details. +/* +/* You should have received a copy of the GNU General Public License +/* along with Parity. If not, see . +*/ + +.centered { + text-align: center; +} diff --git a/js/src/modals/SMSVerification/SendRequest/sendRequest.js b/js/src/modals/SMSVerification/SendRequest/sendRequest.js new file mode 100644 index 000000000..6f9a6077f --- /dev/null +++ b/js/src/modals/SMSVerification/SendRequest/sendRequest.js @@ -0,0 +1,57 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; +import nullable from '../../../util/nullable-proptype'; + +import TxHash from '../../../ui/TxHash'; +import { + POSTING_REQUEST, POSTED_REQUEST, REQUESTING_SMS +} from '../store'; + +import styles from './sendRequest.css'; + +export default class SendRequest extends Component { + static propTypes = { + step: PropTypes.any.isRequired, + tx: nullable(PropTypes.any.isRequired) + } + + render () { + const { step, tx } = this.props; + + switch (step) { + case POSTING_REQUEST: + return (

A verification request will be sent to the contract. Please authorize this using the Parity Signer.

); + + case POSTED_REQUEST: + return ( +
+ +

Please keep this window open.

+
+ ); + + case REQUESTING_SMS: + return ( +

Requesting an SMS from the Parity server.

+ ); + + default: + return null; + } + } +} diff --git a/js/src/modals/SMSVerification/index.js b/js/src/modals/SMSVerification/index.js new file mode 100644 index 000000000..d9b0990db --- /dev/null +++ b/js/src/modals/SMSVerification/index.js @@ -0,0 +1,17 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './SMSVerification'; diff --git a/js/src/modals/SMSVerification/store.js b/js/src/modals/SMSVerification/store.js new file mode 100644 index 000000000..7337f4eac --- /dev/null +++ b/js/src/modals/SMSVerification/store.js @@ -0,0 +1,246 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { observable, computed, autorun, action } from 'mobx'; +import phone from 'phoneformat.js'; +import { sha3 } from '../../api/util/sha3'; + +import Contracts from '../../contracts'; + +import { checkIfVerified, checkIfRequested, postToServer } from '../../contracts/sms-verification'; +import checkIfTxFailed from '../../util/check-if-tx-failed'; +import waitForConfirmations from '../../util/wait-for-block-confirmations'; + +const validCode = /^[A-Z\s]+$/i; + +export const LOADING = 'fetching-contract'; +export const QUERY_DATA = 'query-data'; +export const POSTING_REQUEST = 'posting-request'; +export const POSTED_REQUEST = 'posted-request'; +export const REQUESTING_SMS = 'requesting-sms'; +export const REQUESTED_SMS = 'requested-sms'; +export const QUERY_CODE = 'query-code'; +export const POSTING_CONFIRMATION = 'posting-confirmation'; +export const POSTED_CONFIRMATION = 'posted-confirmation'; +export const DONE = 'done'; + +export default class VerificationStore { + @observable step = null; + @observable error = null; + + @observable contract = null; + @observable fee = null; + @observable isVerified = null; + @observable hasRequested = null; + @observable consentGiven = false; + @observable number = ''; + @observable requestTx = null; + @observable code = ''; + @observable confirmationTx = null; + + @computed get isCodeValid () { + return validCode.test(this.code); + } + @computed get isNumberValid () { + return phone.isValidNumber(this.number); + } + + @computed get isStepValid () { + if (this.step === DONE) { + return true; + } + if (this.error) { + return false; + } + + switch (this.step) { + case LOADING: + return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null; + case QUERY_DATA: + return this.isNumberValid && this.consentGiven; + case REQUESTED_SMS: + return this.requestTx; + case QUERY_CODE: + return this.isCodeValid; + case POSTED_CONFIRMATION: + return this.confirmationTx; + default: + return false; + } + } + + constructor (api, account) { + this.api = api; + this.account = account; + + this.step = LOADING; + Contracts.create(api).registry.getContract('smsVerification') + .then((contract) => { + this.contract = contract; + this.load(); + }) + .catch((err) => { + this.error = 'Failed to fetch the contract: ' + err.message; + }); + + autorun(() => { + if (this.error) { + console.error('sms verification: ' + this.error); + } + }); + } + + @action load = () => { + const { contract, account } = this; + this.step = LOADING; + + const fee = contract.instance.fee.call() + .then((fee) => { + this.fee = fee; + }) + .catch((err) => { + this.error = 'Failed to fetch the fee: ' + err.message; + }); + + const isVerified = checkIfVerified(contract, account) + .then((isVerified) => { + this.isVerified = isVerified; + }) + .catch((err) => { + this.error = 'Failed to check if verified: ' + err.message; + }); + + const hasRequested = checkIfRequested(contract, account) + .then((txHash) => { + this.hasRequested = !!txHash; + if (txHash) { + this.requestTx = txHash; + } + }) + .catch((err) => { + this.error = 'Failed to check if requested: ' + err.message; + }); + + Promise + .all([ fee, isVerified, hasRequested ]) + .then(() => { + this.step = QUERY_DATA; + }); + } + + @action setNumber = (number) => { + this.number = number; + } + + @action setConsentGiven = (consentGiven) => { + this.consentGiven = consentGiven; + } + + @action setCode = (code) => { + this.code = code; + } + + @action sendRequest = () => { + const { api, account, contract, fee, number, hasRequested } = this; + + const request = contract.functions.find((fn) => fn.name === 'request'); + const options = { from: account, value: fee.toString() }; + + let chain = Promise.resolve(); + if (!hasRequested) { + this.step = POSTING_REQUEST; + chain = request.estimateGas(options, []) + .then((gas) => { + options.gas = gas.mul(1.2).toFixed(0); + return request.postTransaction(options, []); + }) + .then((handle) => { + // TODO: The "request rejected" error doesn't have any property to + // distinguish it from other errors, so we can't give a meaningful error here. + return api.pollMethod('parity_checkRequest', handle); + }) + .then((txHash) => { + this.requestTx = txHash; + return checkIfTxFailed(api, txHash, options.gas) + .then((hasFailed) => { + if (hasFailed) { + throw new Error('Transaction failed, all gas used up.'); + } + this.step = POSTED_REQUEST; + return waitForConfirmations(api, txHash, 1); + }); + }); + } + + chain + .then(() => { + this.step = REQUESTING_SMS; + return postToServer({ number, address: account }); + }) + .then(() => { + this.step = REQUESTED_SMS; + }) + .catch((err) => { + this.error = 'Failed to request a confirmation SMS: ' + err.message; + }); + } + + @action queryCode = () => { + this.step = QUERY_CODE; + } + + @action sendConfirmation = () => { + const { api, account, contract, code } = this; + const token = sha3(code); + + const confirm = contract.functions.find((fn) => fn.name === 'confirm'); + const options = { from: account }; + const values = [ token ]; + + this.step = POSTING_CONFIRMATION; + confirm.estimateGas(options, values) + .then((gas) => { + options.gas = gas.mul(1.2).toFixed(0); + return confirm.postTransaction(options, values); + }) + .then((handle) => { + // TODO: The "request rejected" error doesn't have any property to + // distinguish it from other errors, so we can't give a meaningful error here. + return api.pollMethod('parity_checkRequest', handle); + }) + .then((txHash) => { + this.confirmationTx = txHash; + return checkIfTxFailed(api, txHash, options.gas) + .then((hasFailed) => { + if (hasFailed) { + throw new Error('Transaction failed, all gas used up.'); + } + this.step = POSTED_CONFIRMATION; + return waitForConfirmations(api, txHash, 1); + }); + }) + .then(() => { + this.step = DONE; + }) + .catch((err) => { + this.error = 'Failed to send the verification code: ' + err.message; + }); + } + + @action done = () => { + this.step = DONE; + } +} diff --git a/js/src/modals/SMSVerification/terms-of-service.js b/js/src/modals/SMSVerification/terms-of-service.js new file mode 100644 index 000000000..f61b3c97d --- /dev/null +++ b/js/src/modals/SMSVerification/terms-of-service.js @@ -0,0 +1,27 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React from 'react'; + +export default ( +
    +
  • This privacy notice relates to your use of the Parity SMS verification service. We take your privacy seriously and deal in an honest, direct and transparent way when it comes to your data.
  • +
  • We collect your phone number when you use this service. This is temporarily kept in memory, and then encrypted and stored in our EU servers. We only retain the cryptographic hash of the number to prevent duplicated accounts. You consent to this use.
  • +
  • You pay a fee for the cost of this service using the account you want to verify.
  • +
  • Your phone number is transmitted to a third party US SMS verification service Twilio for the sole purpose of the SMS verification. You consent to this use. Twilioโ€™s privacy policy is here: https://www.twilio.com/legal/privacy/developer.
  • +
  • Parity Technology Limited is registered in England and Wales under company number 09760015 and complies with the Data Protection Act 1998 (UK). You may contact us via email at admin@parity.io. Our general privacy policy can be found here: https://ethcore.io/legal.html.
  • +
+); diff --git a/js/src/modals/Transfer/transfer.js b/js/src/modals/Transfer/transfer.js index 506e91930..e41ea08f9 100644 --- a/js/src/modals/Transfer/transfer.js +++ b/js/src/modals/Transfer/transfer.js @@ -28,13 +28,16 @@ import Extras from './Extras'; import ERRORS from './errors'; import styles from './transfer.css'; +import { ERROR_CODES } from '../../api/transport/error'; + const DEFAULT_GAS = '21000'; const DEFAULT_GASPRICE = '20000000000'; const TITLES = { transfer: 'transfer details', sending: 'sending', complete: 'complete', - extras: 'extra information' + extras: 'extra information', + rejected: 'rejected' }; const STAGES_BASIC = [TITLES.transfer, TITLES.sending, TITLES.complete]; const STAGES_EXTRA = [TITLES.transfer, TITLES.extras, TITLES.sending, TITLES.complete]; @@ -74,7 +77,8 @@ export default class Transfer extends Component { valueAll: false, valueError: null, isEth: true, - busyState: null + busyState: null, + rejected: false } componentDidMount () { @@ -82,13 +86,19 @@ export default class Transfer extends Component { } render () { - const { stage, extras } = this.state; + const { stage, extras, rejected } = this.state; + + const steps = [].concat(extras ? STAGES_EXTRA : STAGES_BASIC); + + if (rejected) { + steps[steps.length - 1] = TITLES.rejected; + } return ( + ); + } if (sending) { return ( @@ -314,7 +333,7 @@ export default class Transfer extends Component { } const token = balance.tokens.find((balance) => balance.token.tag === tag).token; - const s = new BigNumber(num).mul(token.format || 1).toString(); + const s = new BigNumber(num).mul(token.format || 1).toFixed(); if (s.indexOf('.') !== -1) { return ERRORS.invalidDecimals; @@ -455,7 +474,17 @@ export default class Transfer extends Component { : this._sendToken() ).then((requestId) => { this.setState({ busyState: 'Waiting for authorization in the Parity Signer' }); - return api.pollMethod('parity_checkRequest', requestId); + + return api + .pollMethod('parity_checkRequest', requestId) + .catch((e) => { + if (e.code === ERROR_CODES.REQUEST_REJECTED) { + this.setState({ rejected: true }); + return false; + } + + throw e; + }); }) .then((txhash) => { this.onNext(); @@ -516,6 +545,13 @@ export default class Transfer extends Component { } recalculateGas = () => { + if (!this.isValid()) { + this.setState({ + gas: '0' + }, this.recalculate); + return; + } + (this.state.isEth ? this._estimateGasEth() : this._estimateGasToken() diff --git a/js/src/modals/index.js b/js/src/modals/index.js index ccecde734..d0f8f7afe 100644 --- a/js/src/modals/index.js +++ b/js/src/modals/index.js @@ -22,6 +22,7 @@ import EditMeta from './EditMeta'; import ExecuteContract from './ExecuteContract'; import FirstRun from './FirstRun'; import Shapeshift from './Shapeshift'; +import SMSVerification from './SMSVerification'; import Transfer from './Transfer'; import PasswordManager from './PasswordManager'; import SaveContract from './SaveContract'; @@ -36,6 +37,7 @@ export { ExecuteContract, FirstRun, Shapeshift, + SMSVerification, Transfer, PasswordManager, LoadContract, diff --git a/js/src/secureApi.js b/js/src/secureApi.js index ed665a5e6..3e1d9eab0 100644 --- a/js/src/secureApi.js +++ b/js/src/secureApi.js @@ -19,12 +19,13 @@ import Api from './api'; const sysuiToken = window.localStorage.getItem('sysuiToken'); export default class SecureApi extends Api { - constructor (url) { + constructor (url, nextToken) { super(new Api.Transport.Ws(url, sysuiToken)); this._isConnecting = true; this._connectState = sysuiToken === 'initial' ? 1 : 0; this._needsToken = false; + this._nextToken = nextToken; this._dappsPort = 8080; this._dappsInterface = null; this._signerPort = 8180; @@ -57,7 +58,11 @@ export default class SecureApi extends Api { if (isConnected) { return this.connectSuccess(); } else if (lastError) { - this.updateToken('initial', 1); + const nextToken = this._nextToken || 'initial'; + const nextState = this._nextToken ? 0 : 1; + + this._nextToken = null; + this.updateToken(nextToken, nextState); } break; diff --git a/js/src/ui/Actionbar/Export/export.js b/js/src/ui/Actionbar/Export/export.js index 64e153734..7f0ea3e15 100644 --- a/js/src/ui/Actionbar/Export/export.js +++ b/js/src/ui/Actionbar/Export/export.js @@ -15,6 +15,7 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; + import FileSaver from 'file-saver'; import FileDownloadIcon from 'material-ui/svg-icons/file/file-download'; @@ -38,19 +39,18 @@ class ActionbarExport extends Component { className={ className } icon={ } label='export' - onClick={ this.onDownloadBackup } /> + onClick={ this.handleExport } + /> ); } - onDownloadBackup = () => { + handleExport = () => { const { filename, content } = this.props; - const text = (typeof content === 'string') - ? content - : JSON.stringify(content, null, 4); + const text = JSON.stringify(content, null, 4); - const blob = new Blob([ text ], { type: 'text/plain;charset=utf-8' }); - FileSaver.saveAs(blob, filename); + const blob = new Blob([ text ], { type: 'application/json' }); + FileSaver.saveAs(blob, `${filename}.json`); } } diff --git a/js/src/ui/Actionbar/Import/import.js b/js/src/ui/Actionbar/Import/import.js index 776e5bb08..081fe1a17 100644 --- a/js/src/ui/Actionbar/Import/import.js +++ b/js/src/ui/Actionbar/Import/import.js @@ -29,6 +29,8 @@ const initialState = { show: false, validate: false, validationBody: null, + error: false, + errorText: '', content: '' }; @@ -65,7 +67,7 @@ export default class ActionbarImport extends Component { renderModal () { const { title, renderValidation } = this.props; - const { show, step } = this.state; + const { show, step, error } = this.state; if (!show) { return null; @@ -73,7 +75,7 @@ export default class ActionbarImport extends Component { const hasSteps = typeof renderValidation === 'function'; - const steps = hasSteps ? [ 'select a file', 'validate' ] : null; + const steps = hasSteps ? [ 'select a file', error ? 'error' : 'validate' ] : null; return ( ); + if (error) { + return [ cancelBtn ]; + } + if (validate) { const confirmBtn = (