From 238b4962f0597f9ee98db503924fb2022dd15c85 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 26 Sep 2016 17:14:44 +0200 Subject: [PATCH 01/14] split journaldb commit into two functions: journal_under and mark_canonical --- util/src/journaldb/archivedb.rs | 11 +- util/src/journaldb/earlymergedb.rs | 217 +++++++++++++------------- util/src/journaldb/overlayrecentdb.rs | 157 ++++++++++--------- util/src/journaldb/refcounteddb.rs | 122 +++++++-------- util/src/journaldb/traits.rs | 18 ++- 5 files changed, 277 insertions(+), 248 deletions(-) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 5f1eb71d438..efedfb766c3 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -35,8 +35,8 @@ const AUX_FLAG: u8 = 255; /// /// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect -/// immediately. Rather some age (based on a linear but arbitrary metric) must pass before -/// the removals actually take effect. +/// immediately. As this is an "archive" database, nothing is ever removed. This means +/// that the states of any block the node has ever processed will be accessible. pub struct ArchiveDB { overlay: MemoryDB, backing: Arc, @@ -156,7 +156,7 @@ impl JournalDB for ArchiveDB { self.latest_era.is_none() } - fn commit(&mut self, batch: &mut DBTransaction, now: u64, _id: &H256, _end: Option<(u64, H256)>) -> Result { + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, _id: &H256) -> Result { let mut inserts = 0usize; let mut deletes = 0usize; @@ -184,6 +184,11 @@ impl JournalDB for ArchiveDB { Ok((inserts + deletes) as u32) } + fn mark_canonical(&mut self, _batch: &mut DBTransaction, _end_era: u64, _canon_id: &H256) -> Result { + // keep everything! it's an archive, after all. + Ok(0) + } + fn inject(&mut self, batch: &mut DBTransaction) -> Result { let mut inserts = 0usize; let mut deletes = 0usize; diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index bbb4ed827d9..ef9868d4130 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -61,6 +61,49 @@ enum RemoveFrom { /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. +/// +/// journal format: +/// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] +/// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] +/// [era, n] => [ ... ] +/// +/// When we make a new commit, we make a journal of all blocks in the recent history and record +/// all keys that were inserted and deleted. The journal is ordered by era; multiple commits can +/// share the same era. This forms a data structure similar to a queue but whose items are tuples. +/// By the time comes to remove a tuple from the queue (i.e. then the era passes from recent history +/// into ancient history) then only one commit from the tuple is considered canonical. This commit +/// is kept in the main backing database, whereas any others from the same era are reverted. +/// +/// It is possible that a key, properly available in the backing database be deleted and re-inserted +/// in the recent history queue, yet have both operations in commits that are eventually non-canonical. +/// To avoid the original, and still required, key from being deleted, we maintain a reference count +/// which includes an original key, if any. +/// +/// The semantics of the `counter` are: +/// insert key k: +/// counter already contains k: count += 1 +/// counter doesn't contain k: +/// backing db contains k: count = 1 +/// backing db doesn't contain k: insert into backing db, count = 0 +/// delete key k: +/// counter contains k (count is asserted to be non-zero): +/// count > 1: counter -= 1 +/// count == 1: remove counter +/// count == 0: remove key from backing db +/// counter doesn't contain k: remove key from backing db +/// +/// Practically, this means that for each commit block turning from recent to ancient we do the +/// following: +/// is_canonical: +/// inserts: Ignored (left alone in the backing database). +/// deletes: Enacted; however, recent history queue is checked for ongoing references. This is +/// reduced as a preference to deletion from the backing database. +/// !is_canonical: +/// inserts: Reverted; however, recent history queue is checked for ongoing references. This is +/// reduced as a preference to deletion from the backing database. +/// deletes: Ignored (they were never inserted). +/// +/// TODO: store_reclaim_period pub struct EarlyMergeDB { overlay: MemoryDB, backing: Arc, @@ -336,55 +379,12 @@ impl JournalDB for EarlyMergeDB { self.backing.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN]).map(|b| b.to_vec()) } - #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] - fn commit(&mut self, batch: &mut DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: - // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, n] => [ ... ] - - // TODO: store reclaim_period. - - // When we make a new commit, we make a journal of all blocks in the recent history and record - // all keys that were inserted and deleted. The journal is ordered by era; multiple commits can - // share the same era. This forms a data structure similar to a queue but whose items are tuples. - // By the time comes to remove a tuple from the queue (i.e. then the era passes from recent history - // into ancient history) then only one commit from the tuple is considered canonical. This commit - // is kept in the main backing database, whereas any others from the same era are reverted. - // - // It is possible that a key, properly available in the backing database be deleted and re-inserted - // in the recent history queue, yet have both operations in commits that are eventually non-canonical. - // To avoid the original, and still required, key from being deleted, we maintain a reference count - // which includes an original key, if any. - // - // The semantics of the `counter` are: - // insert key k: - // counter already contains k: count += 1 - // counter doesn't contain k: - // backing db contains k: count = 1 - // backing db doesn't contain k: insert into backing db, count = 0 - // delete key k: - // counter contains k (count is asserted to be non-zero): - // count > 1: counter -= 1 - // count == 1: remove counter - // count == 0: remove key from backing db - // counter doesn't contain k: remove key from backing db - // - // Practically, this means that for each commit block turning from recent to ancient we do the - // following: - // is_canonical: - // inserts: Ignored (left alone in the backing database). - // deletes: Enacted; however, recent history queue is checked for ongoing references. This is - // reduced as a preference to deletion from the backing database. - // !is_canonical: - // inserts: Reverted; however, recent history queue is checked for ongoing references. This is - // reduced as a preference to deletion from the backing database. - // deletes: Ignored (they were never inserted). - // + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { + let trace = false; // record new commit's details. let mut refs = self.refs.as_ref().unwrap().write(); - let trace = false; + { let mut index = 0usize; let mut last; @@ -403,7 +403,7 @@ impl JournalDB for EarlyMergeDB { let drained = self.overlay.drain(); if trace { - trace!(target: "jdb", "commit: #{} ({}), end era: {:?}", now, id, end); + trace!(target: "jdb", "commit: #{} ({})", now, id); } let removes: Vec = drained @@ -431,86 +431,87 @@ impl JournalDB for EarlyMergeDB { inserts.iter().foreach(|&(k, _)| {r.append(&k);}); r.append(&removes); Self::insert_keys(&inserts, &self.backing, self.column, &mut refs, batch, trace); + + let ins = inserts.iter().map(|&(k, _)| k).collect::>(); + if trace { - let ins = inserts.iter().map(|&(k, _)| k).collect::>(); - trace!(target: "jdb.ops", " Inserts: {:?}", ins); trace!(target: "jdb.ops", " Deletes: {:?}", removes); + trace!(target: "jdb.ops", " Inserts: {:?}", ins); } + batch.put(self.column, &last, r.as_raw()); if self.latest_era.map_or(true, |e| now > e) { batch.put(self.column, &LATEST_ERA_KEY, &encode(&now)); self.latest_era = Some(now); } + + Ok((ins.len() + removes.len()) as u32) } + } - // apply old commits' details - if let Some((end_era, canon_id)) = end { - let mut index = 0usize; - let mut last; - while let Some(rlp_data) = try!(self.backing.get(self.column, { - let mut r = RlpStream::new_list(3); - r.append(&end_era); - r.append(&index); - r.append(&&PADDING[..]); - last = r.drain(); - &last - })) { - let rlp = Rlp::new(&rlp_data); - let inserts: Vec = rlp.val_at(1); + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { + let trace = false; - if canon_id == rlp.val_at(0) { - // Collect keys to be removed. Canon block - remove the (enacted) deletes. - let deletes: Vec = rlp.val_at(2); - if trace { - trace!(target: "jdb.ops", " Expunging: {:?}", deletes); - } - Self::remove_keys(&deletes, &mut refs, batch, self.column, RemoveFrom::Archive, trace); + let mut refs = self.refs.as_ref().unwrap().write(); - if trace { - trace!(target: "jdb.ops", " Finalising: {:?}", inserts); - } - for k in &inserts { - match refs.get(k).cloned() { - None => { - // [in archive] -> SHIFT remove -> SHIFT insert None->Some{queue_refs: 1, in_archive: true} -> TAKE remove Some{queue_refs: 1, in_archive: true}->None -> TAKE insert - // already expunged from the queue (which is allowed since the key is in the archive). - // leave well alone. - } - Some( RefInfo{queue_refs: 1, in_archive: false} ) => { - // just delete the refs entry. - refs.remove(k); - } - Some( RefInfo{queue_refs: x, in_archive: false} ) => { - // must set already in; , - Self::set_already_in(batch, self.column, k); - refs.insert(k.clone(), RefInfo{ queue_refs: x - 1, in_archive: true }); - } - Some( RefInfo{in_archive: true, ..} ) => { - // Invalid! Reinserted the same key twice. - warn!("Key {} inserted twice into same fork.", k); - } + // apply old commits' details + let mut index = 0usize; + let mut last; + + while let Some(rlp_data) = try!(self.backing.get(self.column, { + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })) { + let rlp = Rlp::new(&rlp_data); + let inserts: Vec = rlp.val_at(1); + + if canon_id == &rlp.val_at::(0) { + // Collect keys to be removed. Canon block - remove the (enacted) deletes. + let deletes: Vec = rlp.val_at(2); + trace!(target: "jdb.ops", " Expunging: {:?}", deletes); + Self::remove_keys(&deletes, &mut refs, batch, self.column, RemoveFrom::Archive, trace); + + trace!(target: "jdb.ops", " Finalising: {:?}", inserts); + for k in &inserts { + match refs.get(k).cloned() { + None => { + // [in archive] -> SHIFT remove -> SHIFT insert None->Some{queue_refs: 1, in_archive: true} -> TAKE remove Some{queue_refs: 1, in_archive: true}->None -> TAKE insert + // already expunged from the queue (which is allowed since the key is in the archive). + // leave well alone. + } + Some( RefInfo{queue_refs: 1, in_archive: false} ) => { + // just delete the refs entry. + refs.remove(k); + } + Some( RefInfo{queue_refs: x, in_archive: false} ) => { + // must set already in; , + Self::set_already_in(batch, self.column, k); + refs.insert(k.clone(), RefInfo{ queue_refs: x - 1, in_archive: true }); + } + Some( RefInfo{in_archive: true, ..} ) => { + // Invalid! Reinserted the same key twice. + warn!("Key {} inserted twice into same fork.", k); } } - } else { - // Collect keys to be removed. Non-canon block - remove the (reverted) inserts. - if trace { - trace!(target: "jdb.ops", " Reverting: {:?}", inserts); - } - Self::remove_keys(&inserts, &mut refs, batch, self.column, RemoveFrom::Queue, trace); } - - batch.delete(self.column, &last); - index += 1; - } - if trace { - trace!(target: "jdb", "EarlyMergeDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + } else { + // Collect keys to be removed. Non-canon block - remove the (reverted) inserts. + trace!(target: "jdb.ops", " Reverting: {:?}", inserts); + Self::remove_keys(&inserts, &mut refs, batch, self.column, RemoveFrom::Queue, trace); } - } - if trace { - trace!(target: "jdb", "OK: {:?}", refs.clone()); + batch.delete(self.column, &last); + index += 1; } + trace!(target: "jdb", "EarlyMergeDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + trace!(target: "jdb", "OK: {:?}", refs.clone()); + Ok(0) } diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index bd14eb161bf..0d1149a85ef 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -222,92 +222,107 @@ impl JournalDB for OverlayRecentDB { .or_else(|| self.backing.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN]).map(|b| b.to_vec())) } - fn commit(&mut self, batch: &mut DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // record new commit's details. - trace!("commit: #{} ({}), end era: {:?}", now, id, end); + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { + trace!(target: "journaldb", "entry: #{} ({})", now, id); + let mut journal_overlay = self.journal_overlay.write(); + // flush previous changes journal_overlay.pending_overlay.clear(); - { - let mut r = RlpStream::new_list(3); - let mut tx = self.transaction_overlay.drain(); - let inserted_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c > 0 { Some(k.clone()) } else { None }).collect(); - let removed_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c < 0 { Some(k.clone()) } else { None }).collect(); - // Increase counter for each inserted key no matter if the block is canonical or not. - let insertions = tx.drain().filter_map(|(k, (v, c))| if c > 0 { Some((k, v)) } else { None }); - r.append(id); - r.begin_list(inserted_keys.len()); - for (k, v) in insertions { - r.begin_list(2); - r.append(&k); - r.append(&v); - journal_overlay.backing_overlay.emplace(to_short_key(&k), v); - } - r.append(&removed_keys); - - let mut k = RlpStream::new_list(3); - let index = journal_overlay.journal.get(&now).map_or(0, |j| j.len()); - k.append(&now); - k.append(&index); - k.append(&&PADDING[..]); - batch.put_vec(self.column, &k.drain(), r.out()); - if journal_overlay.latest_era.map_or(true, |e| now > e) { - batch.put_vec(self.column, &LATEST_ERA_KEY, encode(&now).to_vec()); - journal_overlay.latest_era = Some(now); - } - journal_overlay.journal.entry(now).or_insert_with(Vec::new).push(JournalEntry { id: id.clone(), insertions: inserted_keys, deletions: removed_keys }); + + let mut r = RlpStream::new_list(3); + let mut tx = self.transaction_overlay.drain(); + let inserted_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c > 0 { Some(k.clone()) } else { None }).collect(); + let removed_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c < 0 { Some(k.clone()) } else { None }).collect(); + let ops = inserted_keys.len() + removed_keys.len(); + + // Increase counter for each inserted key no matter if the block is canonical or not. + let insertions = tx.drain().filter_map(|(k, (v, c))| if c > 0 { Some((k, v)) } else { None }); + + r.append(id); + r.begin_list(inserted_keys.len()); + for (k, v) in insertions { + r.begin_list(2); + r.append(&k); + r.append(&v); + journal_overlay.backing_overlay.emplace(to_short_key(&k), v); + } + r.append(&removed_keys); + + let mut k = RlpStream::new_list(3); + let index = journal_overlay.journal.get(&now).map_or(0, |j| j.len()); + k.append(&now); + k.append(&index); + k.append(&&PADDING[..]); + batch.put_vec(self.column, &k.drain(), r.out()); + if journal_overlay.latest_era.map_or(true, |e| now > e) { + batch.put_vec(self.column, &LATEST_ERA_KEY, encode(&now).to_vec()); + journal_overlay.latest_era = Some(now); } + journal_overlay.journal.entry(now).or_insert_with(Vec::new).push(JournalEntry { id: id.clone(), insertions: inserted_keys, deletions: removed_keys }); + Ok(ops as u32) + } + + fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { + trace!(target: "journaldb", "canonical: #{} ({})", end_era, canon_id); + + let mut journal_overlay = self.journal_overlay.write(); let journal_overlay = &mut *journal_overlay; + + let mut ops = 0; // apply old commits' details - if let Some((end_era, canon_id)) = end { - if let Some(ref mut records) = journal_overlay.journal.get_mut(&end_era) { - let mut canon_insertions: Vec<(H256, Bytes)> = Vec::new(); - let mut canon_deletions: Vec = Vec::new(); - let mut overlay_deletions: Vec = Vec::new(); - let mut index = 0usize; - for mut journal in records.drain(..) { - //delete the record from the db - let mut r = RlpStream::new_list(3); - r.append(&end_era); - r.append(&index); - r.append(&&PADDING[..]); - batch.delete(self.column, &r.drain()); - trace!("commit: Delete journal for time #{}.{}: {}, (canon was {}): +{} -{} entries", end_era, index, journal.id, canon_id, journal.insertions.len(), journal.deletions.len()); - { - if canon_id == journal.id { - for h in &journal.insertions { - if let Some((d, rc)) = journal_overlay.backing_overlay.raw(&to_short_key(h)) { - if rc > 0 { - canon_insertions.push((h.clone(), d.to_owned())); //TODO: optimize this to avoid data copy - } + if let Some(ref mut records) = journal_overlay.journal.get_mut(&end_era) { + let mut canon_insertions: Vec<(H256, Bytes)> = Vec::new(); + let mut canon_deletions: Vec = Vec::new(); + let mut overlay_deletions: Vec = Vec::new(); + let mut index = 0usize; + for mut journal in records.drain(..) { + //delete the record from the db + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + batch.delete(self.column, &r.drain()); + trace!(target: "journaldb", "Delete journal for time #{}.{}: {}, (canon was {}): +{} -{} entries", end_era, index, journal.id, canon_id, journal.insertions.len(), journal.deletions.len()); + { + if *canon_id == journal.id { + for h in &journal.insertions { + if let Some((d, rc)) = journal_overlay.backing_overlay.raw(&to_short_key(h)) { + if rc > 0 { + canon_insertions.push((h.clone(), d.to_owned())); //TODO: optimize this to avoid data copy } } - canon_deletions = journal.deletions; } - overlay_deletions.append(&mut journal.insertions); + canon_deletions = journal.deletions; } - index += 1; + overlay_deletions.append(&mut journal.insertions); } - // apply canon inserts first - for (k, v) in canon_insertions { - batch.put(self.column, &k, &v); - journal_overlay.pending_overlay.insert(to_short_key(&k), v); - } - // update the overlay - for k in overlay_deletions { - journal_overlay.backing_overlay.remove_and_purge(&to_short_key(&k)); - } - // apply canon deletions - for k in canon_deletions { - if !journal_overlay.backing_overlay.contains(&to_short_key(&k)) { - batch.delete(self.column, &k); - } + index += 1; + } + + ops += canon_insertions.len(); + ops += canon_deletions.len(); + + // apply canon inserts first + for (k, v) in canon_insertions { + batch.put(self.column, &k, &v); + journal_overlay.pending_overlay.insert(to_short_key(&k), v); + } + // update the overlay + for k in overlay_deletions { + journal_overlay.backing_overlay.remove_and_purge(&to_short_key(&k)); + } + // apply canon deletions + for k in canon_deletions { + if !journal_overlay.backing_overlay.contains(&to_short_key(&k)) { + batch.delete(self.column, &k); } } - journal_overlay.journal.remove(&end_era); } - Ok(0) + journal_overlay.journal.remove(&end_era); + + Ok(ops as u32) } fn flush(&self) { diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 5e3f096063e..e6a0f5dccfc 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -34,6 +34,17 @@ use std::env; /// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. +/// +/// journal format: +/// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] +/// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] +/// [era, n] => [ ... ] +/// +/// when we make a new commit, we journal the inserts and removes. +/// for each end_era that we journaled that we are no passing by, +/// we remove all of its removes assuming it is canonical and all +/// of its inserts otherwise. +// TODO: store last_era, reclaim_period. pub struct RefCountedDB { forward: OverlayDB, backing: Arc, @@ -109,77 +120,66 @@ impl JournalDB for RefCountedDB { self.backing.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN]).map(|b| b.to_vec()) } - fn commit(&mut self, batch: &mut DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: - // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, n] => [ ... ] - - // TODO: store last_era, reclaim_period. - - // when we make a new commit, we journal the inserts and removes. - // for each end_era that we journaled that we are no passing by, - // we remove all of its removes assuming it is canonical and all - // of its inserts otherwise. - + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { // record new commit's details. - { - let mut index = 0usize; - let mut last; - - while try!(self.backing.get(self.column, { - let mut r = RlpStream::new_list(3); - r.append(&now); - r.append(&index); - r.append(&&PADDING[..]); - last = r.drain(); - &last - })).is_some() { - index += 1; - } + let mut index = 0usize; + let mut last; + while try!(self.backing.get(self.column, { let mut r = RlpStream::new_list(3); - r.append(id); - r.append(&self.inserts); - r.append(&self.removes); - batch.put(self.column, &last, r.as_raw()); + r.append(&now); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })).is_some() { + index += 1; + } - trace!(target: "rcdb", "new journal for time #{}.{} => {}: inserts={:?}, removes={:?}", now, index, id, self.inserts, self.removes); + let mut r = RlpStream::new_list(3); + r.append(id); + r.append(&self.inserts); + r.append(&self.removes); + batch.put(self.column, &last, r.as_raw()); - self.inserts.clear(); - self.removes.clear(); + let ops = self.inserts.len() + self.removes.len(); - if self.latest_era.map_or(true, |e| now > e) { - batch.put(self.column, &LATEST_ERA_KEY, &encode(&now)); - self.latest_era = Some(now); - } + trace!(target: "rcdb", "new journal for time #{}.{} => {}: inserts={:?}, removes={:?}", now, index, id, self.inserts, self.removes); + + self.inserts.clear(); + self.removes.clear(); + + if self.latest_era.map_or(true, |e| now > e) { + batch.put(self.column, &LATEST_ERA_KEY, &encode(&now)); + self.latest_era = Some(now); } + Ok(ops as u32) + } + + fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { // apply old commits' details - if let Some((end_era, canon_id)) = end { - let mut index = 0usize; - let mut last; - while let Some(rlp_data) = { -// trace!(target: "rcdb", "checking for journal #{}.{}", end_era, index); - try!(self.backing.get(self.column, { - let mut r = RlpStream::new_list(3); - r.append(&end_era); - r.append(&index); - r.append(&&PADDING[..]); - last = r.drain(); - &last - })) - } { - let rlp = Rlp::new(&rlp_data); - let our_id: H256 = rlp.val_at(0); - let to_remove: Vec = rlp.val_at(if canon_id == our_id {2} else {1}); - trace!(target: "rcdb", "delete journal for time #{}.{}=>{}, (canon was {}): deleting {:?}", end_era, index, our_id, canon_id, to_remove); - for i in &to_remove { - self.forward.remove(i); - } - batch.delete(self.column, &last); - index += 1; + let mut index = 0usize; + let mut last; + while let Some(rlp_data) = { + try!(self.backing.get(self.column, { + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })) + } { + let rlp = Rlp::new(&rlp_data); + let our_id: H256 = rlp.val_at(0); + let to_remove: Vec = rlp.val_at(if *canon_id == our_id {2} else {1}); + trace!(target: "rcdb", "delete journal for time #{}.{}=>{}, (canon was {}): deleting {:?}", end_era, index, our_id, canon_id, to_remove); + for i in &to_remove { + self.forward.remove(i); } + batch.delete(self.column, &last); + index += 1; } let r = try!(self.forward.commit_to_batch(batch)); diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index 85cc7fe58b5..afa2bb9f46d 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -35,9 +35,12 @@ pub trait JournalDB: HashDB { /// Get the latest era in the DB. None if there isn't yet any data in there. fn latest_era(&self) -> Option; - /// Commit all recent insert operations and canonical historical commits' removals from the - /// old era to the backing database, reverting any non-canonical historical commit's inserts. - fn commit(&mut self, batch: &mut DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result; + /// Journal recent database operations as being associated with a given era and id. + // TODO: give the overlay to this function so journaldbs don't manage the overlays themeselves. + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result; + + /// Mark a given block as canonical, indicating that competing blocks' states may be pruned out. + fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> Result; /// Commit all queued insert and delete operations without affecting any journalling -- this requires that all insertions /// and deletions are indeed canonical and will likely lead to an invalid database if that assumption is violated. @@ -68,8 +71,13 @@ pub trait JournalDB: HashDB { #[cfg(test)] fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { let mut batch = self.backing().transaction(); - let res = try!(self.commit(&mut batch, now, id, end)); - let result = self.backing().write(batch).map(|_| res).map_err(Into::into); + let mut ops = try!(self.journal_under(&mut batch, now, id)); + + if let Some((end_era, canon_id)) = end { + ops += try!(self.mark_canonical(&mut batch, end_era, &canon_id)); + } + + let result = self.backing().write(batch).map(|_| ops).map_err(Into::into); self.flush(); result } From e26a16c70c85314b60fd41418b8f4c691d9287b2 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 26 Sep 2016 17:27:48 +0200 Subject: [PATCH 02/14] use new commit mechanism in client --- ethcore/src/client/client.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a60cce01db2..57d8b6fbcb6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -175,7 +175,7 @@ impl Client { let mut state_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE); if state_db.is_empty() && try!(spec.ensure_db_good(state_db.as_hashdb_mut())) { let mut batch = DBTransaction::new(&db); - try!(state_db.commit(&mut batch, 0, &spec.genesis_header().hash(), None)); + try!(state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash())); try!(db.write(batch).map_err(ClientError::Database)); } @@ -421,13 +421,6 @@ impl Client { let number = block.header().number(); let parent = block.header().parent_hash().clone(); let chain = self.chain.read(); - // Are we committing an era? - let ancient = if number >= HISTORY { - let n = number - HISTORY; - Some((n, chain.block_hash(n).unwrap())) - } else { - None - }; // Commit results let receipts = block.receipts().to_owned(); @@ -442,7 +435,14 @@ impl Client { // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. // TODO: Prove it with a test. - block.drain().commit(&mut batch, number, hash, ancient).expect("DB commit failed."); + let mut db = block.drain(); + + db.journal_under(&mut batch, number, hash).expect("DB commit failed"); + + if number >= HISTORY { + let n = number - HISTORY; + db.mark_canonical(&mut batch, n, &chain.block_hash(n).unwrap()).expect("DB commit failed"); + } let route = chain.insert_block(&mut batch, block_data, receipts); self.tracedb.read().import(&mut batch, TraceImportRequest { From 4581469e780498b6e179e6ccdde6d3a0f6daa040 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 13 Oct 2016 23:28:56 +0200 Subject: [PATCH 03/14] mitigate refcell conflict in state diffing (#2601) * mitigate refcell conflict in state diffing Also uses RefCell::get_mut in a few places. * Add test case --- ethcore/src/state/mod.rs | 44 +++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 39c8bbc1114..6e34e93676b 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -239,15 +239,15 @@ impl State { /// Create a recoverable snaphot of this state. pub fn snapshot(&mut self) { - self.snapshots.borrow_mut().push(HashMap::new()); + self.snapshots.get_mut().push(HashMap::new()); } /// Merge last snapshot with previous. pub fn discard_snapshot(&mut self) { // merge with previous snapshot - let last = self.snapshots.borrow_mut().pop(); + let last = self.snapshots.get_mut().pop(); if let Some(mut snapshot) = last { - if let Some(ref mut prev) = self.snapshots.borrow_mut().last_mut() { + if let Some(ref mut prev) = self.snapshots.get_mut().last_mut() { if prev.is_empty() { **prev = snapshot; } else { @@ -261,11 +261,11 @@ impl State { /// Revert to the last snapshot and discard it. pub fn revert_to_snapshot(&mut self) { - if let Some(mut snapshot) = self.snapshots.borrow_mut().pop() { + if let Some(mut snapshot) = self.snapshots.get_mut().pop() { for (k, v) in snapshot.drain() { match v { Some(v) => { - match self.cache.borrow_mut().entry(k) { + match self.cache.get_mut().entry(k) { Entry::Occupied(mut e) => { // Merge snapshotted changes back into the main account // storage preserving the cache. @@ -277,7 +277,7 @@ impl State { } }, None => { - match self.cache.borrow_mut().entry(k) { + match self.cache.get_mut().entry(k) { Entry::Occupied(e) => { if e.get().is_dirty() { e.remove(); @@ -578,14 +578,14 @@ impl State { } fn query_pod(&mut self, query: &PodState) { - for (address, pod_account) in query.get() { - self.ensure_cached(address, RequireCache::Code, |a| { - if a.is_some() { - for key in pod_account.storage.keys() { - self.storage_at(address, key); - } - } - }); + for (address, pod_account) in query.get().into_iter() + .filter(|&(ref a, _)| self.ensure_cached(a, RequireCache::Code, |a| a.is_some())) + { + // needs to be split into two parts for the refcell code here + // to work. + for key in pod_account.storage.keys() { + self.storage_at(address, key); + } } } @@ -1797,4 +1797,20 @@ fn create_empty() { assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); } +#[test] +fn should_not_panic_on_state_diff_with_storage() { + let state = get_temp_state(); + let mut state = state.reference().clone(); + + let a: Address = 0xa.into(); + state.init_code(&a, b"abcdefg".to_vec()); + state.add_balance(&a, &256.into()); + state.set_storage(&a, 0xb.into(), 0xc.into()); + + let mut new_state = state.clone(); + new_state.set_storage(&a, 0xb.into(), 0xd.into()); + + new_state.diff_from(state); +} + } From dbc25cf4e72cb4ffef9044e17279e7da907646e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 14 Oct 2016 13:55:48 +0200 Subject: [PATCH 04/14] Additional logs when transactions is removed from queue (#2617) --- ethcore/src/miner/transaction_queue.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index fdb652780a6..f7f84435928 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -678,6 +678,8 @@ impl TransactionQueue { let nonce = transaction.nonce(); let current_nonce = fetch_account(&sender).nonce; + trace!(target: "txqueue", "Removing invalid transaction: {:?}", transaction.hash()); + // Remove from future let order = self.future.drop(&sender, &nonce); if order.is_some() { @@ -953,12 +955,14 @@ impl TransactionQueue { let old_fee = old.gas_price; let new_fee = order.gas_price; if old_fee.cmp(&new_fee) == Ordering::Greater { + trace!(target: "txqueue", "Didn't insert transaction because gas price was too low: {:?} ({:?} stays in the queue)", order.hash, old.hash); // Put back old transaction since it has greater priority (higher gas_price) set.insert(address, nonce, old); // and remove new one by_hash.remove(&order.hash).expect("The hash has been just inserted and no other line is altering `by_hash`."); false } else { + trace!(target: "txqueue", "Replaced transaction: {:?} with transaction with higher gas price: {:?}", old.hash, order.hash); // Make sure we remove old transaction entirely by_hash.remove(&old.hash).expect("The hash is coming from `future` so it has to be in `by_hash`."); true From f9440f20b80b0b11adada80c7ed2a4def072182c Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 14 Oct 2016 13:56:00 +0200 Subject: [PATCH 05/14] Fixed tx queue limit for local transactions (#2616) * Fixed tx queue limit for local tx * Fixing test * Increas gas limit to 20x --- ethcore/src/miner/miner.rs | 4 ++-- ethcore/src/miner/transaction_queue.rs | 11 ++++++++--- parity/cli/usage.txt | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index a2dab447518..08d84b6378a 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -462,8 +462,8 @@ impl Miner { let mut queue = self.transaction_queue.lock(); queue.set_gas_limit(gas_limit); if let GasLimit::Auto = self.options.tx_queue_gas_limit { - // Set total tx queue gas limit to be 2x the block gas limit. - queue.set_total_gas_limit(gas_limit << 1); + // Set total tx queue gas limit to be 20x the block gas limit. + queue.set_total_gas_limit(gas_limit * 20.into()); } } diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index f7f84435928..15fe38236ed 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -326,14 +326,14 @@ impl TransactionSet { let to_drop : Vec<(Address, U256)> = { self.by_priority .iter() - .skip_while(|order| { + .filter(|order| { count = count + 1; let r = gas.overflowing_add(order.gas); if r.1 { return false } gas = r.0; // Own and retracted transactions are allowed to go above the gas limit, bot not above the count limit. - (gas <= self.gas_limit || order.origin == TransactionOrigin::Local || order.origin == TransactionOrigin::RetractedBlock) && - count <= self.limit + (gas > self.gas_limit && order.origin != TransactionOrigin::Local && order.origin != TransactionOrigin::RetractedBlock) || + count > self.limit }) .map(|order| by_hash.get(&order.hash) .expect("All transactions in `self.by_priority` and `self.by_address` are kept in sync with `by_hash`.")) @@ -345,6 +345,7 @@ impl TransactionSet { .fold(HashMap::new(), |mut removed, (sender, nonce)| { let order = self.drop(&sender, &nonce) .expect("Transaction has just been found in `by_priority`; so it is in `by_address` also."); + trace!(target: "txqueue", "Dropped out of limit transaction: {:?}", order.hash); by_hash.remove(&order.hash) .expect("hash is in `by_priorty`; all hashes in `by_priority` must be in `by_hash`; qed"); @@ -1782,8 +1783,12 @@ mod test { let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero()); let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); + let (tx5, tx6) = new_tx_pair_default(U256::from(1), U256::from(2)); txq.add(tx1.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); txq.add(tx2.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); + txq.add(tx5.clone(), &default_account_details, TransactionOrigin::External).unwrap(); + // Not accepted because of limit + txq.add(tx6.clone(), &default_account_details, TransactionOrigin::External).unwrap_err(); txq.add(tx3.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); txq.add(tx4.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); assert_eq!(txq.status().pending, 4); diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index 75501cdd199..c2eb51ade27 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -186,7 +186,7 @@ Sealing/Mining Options: to be included in next block) (default: {flag_tx_queue_size}). --tx-queue-gas LIMIT Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or - 'auto' or 'off'. 'auto' sets the limit to be 2x + 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit. (default: {flag_tx_queue_gas}). --remove-solved Move solved blocks from the work package queue instead of cloning them. This gives a slightly From 8ad1582208c1fcee803f14acd85c7b3fc42e8a03 Mon Sep 17 00:00:00 2001 From: keorn Date: Fri, 14 Oct 2016 13:28:02 +0100 Subject: [PATCH 06/14] enable suicide json test (#2626) --- ethcore/res/ethereum/tests | 2 +- ethcore/src/json_tests/homestead_chain.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 8f07dbc8294..c63dc0e22ea 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 8f07dbc8294a32db5ebe8098925fcefc2eab3e71 +Subproject commit c63dc0e22eab0c3a40e09a87391e07e103014058 diff --git a/ethcore/src/json_tests/homestead_chain.rs b/ethcore/src/json_tests/homestead_chain.rs index 314c36cf177..37a9d0a21a1 100644 --- a/ethcore/src/json_tests/homestead_chain.rs +++ b/ethcore/src/json_tests/homestead_chain.rs @@ -37,6 +37,5 @@ declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/ declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"} declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"} declare_test!{BlockchainTests_Homestead_bcShanghaiLove, "BlockchainTests/Homestead/bcShanghaiLove"} -// Uncomment once the test is correct. -// declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"} +declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"} declare_test!{BlockchainTests_Homestead_bcExploitTest, "BlockchainTests/Homestead/bcExploitTest"} From 835cd13c0ef8fc411d06a7414163c4e57d748e82 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 14 Oct 2016 14:44:11 +0200 Subject: [PATCH 07/14] Database performance tweaks (#2619) --- Cargo.lock | 4 ++-- ethcore/src/state_db.rs | 3 +-- util/src/kvdb.rs | 19 ++++++++++++------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9550d6ddddc..cee71272771 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1406,7 +1406,7 @@ dependencies = [ [[package]] name = "rocksdb" version = "0.4.5" -source = "git+https://github.com/ethcore/rust-rocksdb#ffc7c82380fe8569f85ae6743f7f620af2d4a679" +source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58" dependencies = [ "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)", @@ -1415,7 +1415,7 @@ dependencies = [ [[package]] name = "rocksdb-sys" version = "0.3.0" -source = "git+https://github.com/ethcore/rust-rocksdb#ffc7c82380fe8569f85ae6743f7f620af2d4a679" +source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58" dependencies = [ "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 4358dbb42f3..01f3845709d 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -31,8 +31,7 @@ pub const DEFAULT_ACCOUNT_PRESET: usize = 1000000; pub const ACCOUNT_BLOOM_HASHCOUNT_KEY: &'static [u8] = b"account_hash_count"; -const STATE_CACHE_BLOCKS: usize = 8; - +const STATE_CACHE_BLOCKS: usize = 12; /// Shared canonical state cache. struct AccountCache { diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index df36918dd93..92b7e9fbd7d 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -23,7 +23,7 @@ use std::default::Default; use std::path::PathBuf; use rlp::{UntrustedRlp, RlpType, View, Compressible}; use rocksdb::{DB, Writable, WriteBatch, WriteOptions, IteratorMode, DBIterator, - Options, DBCompactionStyle, BlockBasedOptions, Direction, Cache, Column}; + Options, DBCompactionStyle, BlockBasedOptions, Direction, Cache, Column, ReadOptions}; const DB_BACKGROUND_FLUSHES: i32 = 2; const DB_BACKGROUND_COMPACTIONS: i32 = 2; @@ -207,6 +207,7 @@ pub struct Database { db: RwLock>, config: DatabaseConfig, write_opts: WriteOptions, + read_opts: ReadOptions, overlay: RwLock, KeyState>>>, path: String, } @@ -227,6 +228,7 @@ impl Database { try!(opts.set_parsed_options(&format!("rate_limiter_bytes_per_sec={}", rate_limit))); } try!(opts.set_parsed_options(&format!("max_total_wal_size={}", 64 * 1024 * 1024))); + try!(opts.set_parsed_options("verify_checksums_in_compaction=0")); opts.set_max_open_files(config.max_open_files); opts.create_if_missing(true); opts.set_use_fsync(false); @@ -264,6 +266,8 @@ impl Database { if !config.wal { write_opts.disable_wal(true); } + let mut read_opts = ReadOptions::new(); + read_opts.set_verify_checksums(false); let mut cfs: Vec = Vec::new(); let db = match config.columns { @@ -307,6 +311,7 @@ impl Database { write_opts: write_opts, overlay: RwLock::new((0..(num_cols + 1)).map(|_| HashMap::new()).collect()), path: path.to_owned(), + read_opts: read_opts, }) } @@ -421,8 +426,8 @@ impl Database { Some(&KeyState::Delete) => Ok(None), None => { col.map_or_else( - || db.get(key).map(|r| r.map(|v| v.to_vec())), - |c| db.get_cf(cfs[c as usize], key).map(|r| r.map(|v| v.to_vec()))) + || db.get_opt(key, &self.read_opts).map(|r| r.map(|v| v.to_vec())), + |c| db.get_cf_opt(cfs[c as usize], key, &self.read_opts).map(|r| r.map(|v| v.to_vec()))) }, } }, @@ -435,8 +440,8 @@ impl Database { pub fn get_by_prefix(&self, col: Option, prefix: &[u8]) -> Option> { match *self.db.read() { Some(DBAndColumns { ref db, ref cfs }) => { - let mut iter = col.map_or_else(|| db.iterator(IteratorMode::From(prefix, Direction::Forward)), - |c| db.iterator_cf(cfs[c as usize], IteratorMode::From(prefix, Direction::Forward)).unwrap()); + let mut iter = col.map_or_else(|| db.iterator_opt(IteratorMode::From(prefix, Direction::Forward), &self.read_opts), + |c| db.iterator_cf_opt(cfs[c as usize], IteratorMode::From(prefix, Direction::Forward), &self.read_opts).unwrap()); match iter.next() { // TODO: use prefix_same_as_start read option (not availabele in C API currently) Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Some(v) } else { None }, @@ -452,8 +457,8 @@ impl Database { //TODO: iterate over overlay match *self.db.read() { Some(DBAndColumns { ref db, ref cfs }) => { - col.map_or_else(|| DatabaseIterator { iter: db.iterator(IteratorMode::Start) }, - |c| DatabaseIterator { iter: db.iterator_cf(cfs[c as usize], IteratorMode::Start).unwrap() }) + col.map_or_else(|| DatabaseIterator { iter: db.iterator_opt(IteratorMode::Start, &self.read_opts) }, + |c| DatabaseIterator { iter: db.iterator_cf_opt(cfs[c as usize], IteratorMode::Start, &self.read_opts).unwrap() }) }, None => panic!("Not supported yet") //TODO: return an empty iterator or change return type } From f28b8352c1e7c7b9d83409ff4aafa936314105dc Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 14 Oct 2016 14:44:56 +0200 Subject: [PATCH 08/14] Configurable history size in master (#2606) * split journaldb commit into two functions: journal_under and mark_canonical * use new commit mechanism in client * Configurable history size in master * Reduce DB history * Configurable history size * Set min history size * Test * Fixed a test and reduced the limit --- ethcore/src/block.rs | 4 +++ ethcore/src/client/client.rs | 50 +++++++++++++++++++++------ ethcore/src/client/config.rs | 2 ++ ethcore/src/snapshot/service.rs | 2 +- ethcore/src/tests/client.rs | 25 ++++++++++++++ parity/blockchain.rs | 6 ++-- parity/cli/config.full.toml | 1 + parity/cli/config.toml | 1 + parity/cli/mod.rs | 5 +++ parity/cli/usage.txt | 2 ++ parity/configuration.rs | 10 ++++++ parity/helpers.rs | 2 ++ parity/run.rs | 2 ++ parity/snapshot.rs | 3 +- util/src/journaldb/overlayrecentdb.rs | 15 ++++++-- util/src/journaldb/traits.rs | 3 ++ 16 files changed, 116 insertions(+), 17 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 80c35d1d0aa..5cd9835114f 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -404,6 +404,10 @@ impl<'x> OpenBlock<'x> { uncle_bytes: uncle_bytes, } } + + #[cfg(test)] + /// Return mutable block reference. To be used in tests only. + pub fn block_mut (&mut self) -> &mut ExecutedBlock { &mut self.block } } impl<'x> IsBlock for OpenBlock<'x> { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 1cf6151c291..f5d10266f24 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -74,6 +74,7 @@ pub use blockchain::CacheSize as BlockChainCacheSize; const MAX_TX_QUEUE_SIZE: usize = 4096; const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2; +const MIN_HISTORY_SIZE: u64 = 8; impl fmt::Display for BlockChainInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -141,12 +142,9 @@ pub struct Client { queue_transactions: AtomicUsize, last_hashes: RwLock>, factories: Factories, + history: u64, } -/// The pruning constant -- how old blocks must be before we -/// assume finality of a given candidate. -pub const HISTORY: u64 = 1200; - impl Client { /// Create a new client with given spec and DB path and custom verifier. pub fn new( @@ -177,6 +175,28 @@ impl Client { try!(db.write(batch).map_err(ClientError::Database)); } + trace!("Cleanup journal: DB Earliest = {:?}, Latest = {:?}", state_db.journal_db().earliest_era(), state_db.journal_db().latest_era()); + + let history = if config.history < MIN_HISTORY_SIZE { + info!(target: "client", "Ignoring pruning history parameter of {}\ + , falling back to minimum of {}", + config.history, MIN_HISTORY_SIZE); + MIN_HISTORY_SIZE + } else { + config.history + }; + + if let (Some(earliest), Some(latest)) = (state_db.journal_db().earliest_era(), state_db.journal_db().latest_era()) { + if latest > earliest && latest - earliest > history { + for era in earliest..(latest - history + 1) { + trace!("Removing era {}", era); + let mut batch = DBTransaction::new(&db); + try!(state_db.mark_canonical(&mut batch, era, &chain.block_hash(era).expect("Old block not found in the database"))); + try!(db.write(batch).map_err(ClientError::Database)); + } + } + } + if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(h.state_root())) { warn!("State root not found for block #{} ({})", chain.best_block_number(), chain.best_block_hash().hex()); } @@ -217,6 +237,7 @@ impl Client { queue_transactions: AtomicUsize::new(0), last_hashes: RwLock::new(VecDeque::new()), factories: factories, + history: history, }; Ok(Arc::new(client)) } @@ -275,7 +296,7 @@ impl Client { let chain = self.chain.read(); // Check the block isn't so old we won't be able to enact it. let best_block_number = chain.best_block_number(); - if best_block_number >= HISTORY && header.number() <= best_block_number - HISTORY { + if best_block_number >= self.history && header.number() <= best_block_number - self.history { warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number); return Err(()); } @@ -432,8 +453,8 @@ impl Client { state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - if number >= HISTORY { - let n = number - HISTORY; + if number >= self.history { + let n = number - self.history; state.mark_canonical(&mut batch, n, &chain.block_hash(n).unwrap()).expect("DB commit failed"); } @@ -495,7 +516,7 @@ impl Client { let db = self.state_db.lock().boxed_clone(); // early exit for pruned blocks - if db.is_pruned() && self.chain.read().best_block_number() >= block_number + HISTORY { + if db.is_pruned() && self.chain.read().best_block_number() >= block_number + self.history { return None; } @@ -600,7 +621,7 @@ impl Client { let best_block_number = self.chain_info().best_block_number; let block_number = try!(self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at))); - if best_block_number > HISTORY + block_number && db.is_pruned() { + if best_block_number > self.history + block_number && db.is_pruned() { return Err(snapshot::Error::OldBlockPrunedDB.into()); } @@ -612,8 +633,10 @@ impl Client { 0 }; - self.block_hash(BlockID::Number(start_num)) - .expect("blocks within HISTORY are always stored.") + match self.block_hash(BlockID::Number(start_num)) { + Some(h) => h, + None => return Err(snapshot::Error::InvalidStartingBlock(at).into()), + } } _ => match self.block_hash(at) { Some(hash) => hash, @@ -626,6 +649,11 @@ impl Client { Ok(()) } + /// Ask the client what the history parameter is. + pub fn pruning_history(&self) -> u64 { + self.history + } + fn block_hash(chain: &BlockChain, id: BlockID) -> Option { match id { BlockID::Hash(hash) => Some(hash), diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index e0ac51f0ad4..69b9d9efe4c 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -110,6 +110,8 @@ pub struct ClientConfig { pub state_cache_size: usize, /// EVM jump-tables cache size. pub jump_table_size: usize, + /// State pruning history size. + pub history: u64, } #[cfg(test)] diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 5243a47929f..63232ad5bde 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -346,7 +346,7 @@ impl Service { self.taking_snapshot.store(false, Ordering::SeqCst); if let Err(e) = res { - if client.chain_info().best_block_number >= num + ::client::HISTORY { + if client.chain_info().best_block_number >= num + client.pruning_history() { // "Cancelled" is mincing words a bit -- what really happened // is that the state we were snapshotting got pruned out // before we could finish. diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 067f28d3918..de99d6d057e 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -24,6 +24,7 @@ use common::*; use devtools::*; use miner::Miner; use rlp::{Rlp, View}; +use spec::Spec; #[test] fn imports_from_empty() { @@ -238,3 +239,27 @@ fn can_mine() { assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); } + +#[test] +fn change_history_size() { + let dir = RandomTempPath::new(); + let test_spec = Spec::new_null(); + let mut config = ClientConfig::default(); + let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); + config.history = 2; + let address = Address::random(); + { + let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap(); + for _ in 0..20 { + let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]); + b.block_mut().fields_mut().state.add_balance(&address, &5.into()); + b.block_mut().fields_mut().state.commit().unwrap(); + let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap(); + client.import_sealed_block(b).unwrap(); // account change is in the journal overlay + } + } + let mut config = ClientConfig::default(); + config.history = 10; + let client = Client::new(config, &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap(); + assert_eq!(client.state().balance(&address), 100.into()); +} diff --git a/parity/blockchain.rs b/parity/blockchain.rs index d4a4d8217bc..1909450ba37 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -77,6 +77,7 @@ pub struct ImportBlockchain { pub file_path: Option, pub format: Option, pub pruning: Pruning, + pub pruning_history: u64, pub compaction: DatabaseCompactionProfile, pub wal: bool, pub mode: Mode, @@ -94,6 +95,7 @@ pub struct ExportBlockchain { pub file_path: Option, pub format: Option, pub pruning: Pruning, + pub pruning_history: u64, pub compaction: DatabaseCompactionProfile, pub wal: bool, pub mode: Mode, @@ -156,7 +158,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result { try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile())); // prepare client config - let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), algorithm); + let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), algorithm, cmd.pruning_history); // build client let service = try!(ClientService::start( @@ -307,7 +309,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result { try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile())); // prepare client config - let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, VMType::default(), "".into(), algorithm); + let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, VMType::default(), "".into(), algorithm, cmd.pruning_history); let service = try!(ClientService::start( client_config, diff --git a/parity/cli/config.full.toml b/parity/cli/config.full.toml index 8cbfadef46f..3a9531bcff2 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -77,6 +77,7 @@ notify_work = ["http://localhost:3001"] [footprint] tracing = "auto" pruning = "auto" +pruning_history = 64 cache_size_db = 64 cache_size_blocks = 8 cache_size_queue = 50 diff --git a/parity/cli/config.toml b/parity/cli/config.toml index d54b0254cf5..d9608640c89 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -46,6 +46,7 @@ tx_queue_gas = "auto" [footprint] tracing = "on" pruning = "fast" +pruning_history = 64 cache_size_db = 128 cache_size_blocks = 16 cache_size_queue = 100 diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index f1f9efa8425..c4ec4135cf9 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -207,6 +207,8 @@ usage! { or |c: &Config| otry!(c.footprint).tracing.clone(), flag_pruning: String = "auto", or |c: &Config| otry!(c.footprint).pruning.clone(), + flag_pruning_history: u64 = 64u64, + or |c: &Config| otry!(c.footprint).pruning_history.clone(), flag_cache_size_db: u32 = 64u32, or |c: &Config| otry!(c.footprint).cache_size_db.clone(), flag_cache_size_blocks: u32 = 8u32, @@ -361,6 +363,7 @@ struct Mining { struct Footprint { tracing: Option, pruning: Option, + pruning_history: Option, fast_and_loose: Option, cache_size: Option, cache_size_db: Option, @@ -536,6 +539,7 @@ mod tests { // -- Footprint Options flag_tracing: "auto".into(), flag_pruning: "auto".into(), + flag_pruning_history: 64u64, flag_cache_size_db: 64u32, flag_cache_size_blocks: 8u32, flag_cache_size_queue: 50u32, @@ -690,6 +694,7 @@ mod tests { footprint: Some(Footprint { tracing: Some("on".into()), pruning: Some("fast".into()), + pruning_history: Some(64), fast_and_loose: None, cache_size: None, cache_size_db: Some(128), diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index c2eb51ade27..4f416e10db4 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -209,6 +209,8 @@ Footprint Options: fast - maintain journal overlay. Fast but 50MB used. auto - use the method most recently synced or default to fast if none synced (default: {flag_pruning}). + --pruning-history NUM Set a number of recent states to keep when pruning + is active. [default: {flag_pruning_history}]. --cache-size-db MB Override database cache size (default: {flag_cache_size_db}). --cache-size-blocks MB Specify the prefered size of the blockchain cache in megabytes (default: {flag_cache_size_blocks}). diff --git a/parity/configuration.rs b/parity/configuration.rs index ffcea2c60ec..5303b12019e 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -73,6 +73,7 @@ impl Configuration { pub fn into_command(self) -> Result { let dirs = self.directories(); let pruning = try!(self.args.flag_pruning.parse()); + let pruning_history = self.args.flag_pruning_history; let vm_type = try!(self.vm_type()); let mode = try!(to_mode(&self.args.flag_mode, self.args.flag_mode_timeout, self.args.flag_mode_alarm)); let miner_options = try!(self.miner_options()); @@ -145,6 +146,7 @@ impl Configuration { file_path: self.args.arg_file.clone(), format: format, pruning: pruning, + pruning_history: pruning_history, compaction: compaction, wal: wal, mode: mode, @@ -162,6 +164,7 @@ impl Configuration { file_path: self.args.arg_file.clone(), format: format, pruning: pruning, + pruning_history: pruning_history, compaction: compaction, wal: wal, mode: mode, @@ -177,6 +180,7 @@ impl Configuration { dirs: dirs, spec: spec, pruning: pruning, + pruning_history: pruning_history, logger_config: logger_config, mode: mode, tracing: tracing, @@ -194,6 +198,7 @@ impl Configuration { dirs: dirs, spec: spec, pruning: pruning, + pruning_history: pruning_history, logger_config: logger_config, mode: mode, tracing: tracing, @@ -217,6 +222,7 @@ impl Configuration { dirs: dirs, spec: spec, pruning: pruning, + pruning_history: pruning_history, daemon: daemon, logger_config: logger_config, miner_options: miner_options, @@ -721,6 +727,7 @@ mod tests { file_path: Some("blockchain.json".into()), format: Default::default(), pruning: Default::default(), + pruning_history: 64, compaction: Default::default(), wal: true, mode: Default::default(), @@ -741,6 +748,7 @@ mod tests { dirs: Default::default(), file_path: Some("blockchain.json".into()), pruning: Default::default(), + pruning_history: 64, format: Default::default(), compaction: Default::default(), wal: true, @@ -763,6 +771,7 @@ mod tests { dirs: Default::default(), file_path: Some("blockchain.json".into()), pruning: Default::default(), + pruning_history: 64, format: Some(DataFormat::Hex), compaction: Default::default(), wal: true, @@ -791,6 +800,7 @@ mod tests { dirs: Default::default(), spec: Default::default(), pruning: Default::default(), + pruning_history: 64, daemon: None, logger_config: Default::default(), miner_options: Default::default(), diff --git a/parity/helpers.rs b/parity/helpers.rs index 6c02d4e5ac5..c8a985105c2 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -205,6 +205,7 @@ pub fn to_client_config( vm_type: VMType, name: String, pruning: Algorithm, + pruning_history: u64, ) -> ClientConfig { let mut client_config = ClientConfig::default(); @@ -232,6 +233,7 @@ pub fn to_client_config( client_config.tracing.enabled = tracing; client_config.fat_db = fat_db; client_config.pruning = pruning; + client_config.history = pruning_history; client_config.db_compaction = compaction; client_config.db_wal = wal; client_config.vm_type = vm_type; diff --git a/parity/run.rs b/parity/run.rs index 254765983b9..4610b6f2e7b 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -61,6 +61,7 @@ pub struct RunCmd { pub dirs: Directories, pub spec: SpecType, pub pruning: Pruning, + pub pruning_history: u64, /// Some if execution should be daemonized. Contains pid_file path. pub daemon: Option, pub logger_config: LogConfig, @@ -193,6 +194,7 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> { cmd.vm_type, cmd.name, algorithm, + cmd.pruning_history, ); // set up bootnodes diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 6b2efeed582..dd5c611d30c 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -54,6 +54,7 @@ pub struct SnapshotCommand { pub dirs: Directories, pub spec: SpecType, pub pruning: Pruning, + pub pruning_history: u64, pub logger_config: LogConfig, pub mode: Mode, pub tracing: Switch, @@ -162,7 +163,7 @@ impl SnapshotCommand { try!(execute_upgrades(&db_dirs, algorithm, self.compaction.compaction_profile())); // prepare client config - let client_config = to_client_config(&self.cache_config, self.mode, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm); + let client_config = to_client_config(&self.cache_config, self.mode, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm, self.pruning_history); let service = try!(ClientService::start( client_config, diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index 0d1149a85ef..bf01567fb88 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -70,6 +70,7 @@ struct JournalOverlay { pending_overlay: H256FastMap, // Nodes being transfered from backing_overlay to backing db journal: HashMap>, latest_era: Option, + earliest_era: Option, } #[derive(PartialEq)] @@ -123,7 +124,10 @@ impl OverlayRecentDB { fn can_reconstruct_refs(&self) -> bool { let reconstructed = Self::read_overlay(&self.backing, self.column); let journal_overlay = self.journal_overlay.read(); - *journal_overlay == reconstructed + journal_overlay.backing_overlay == reconstructed.backing_overlay && + journal_overlay.pending_overlay == reconstructed.pending_overlay && + journal_overlay.journal == reconstructed.journal && + journal_overlay.latest_era == reconstructed.latest_era } fn payload(&self, key: &H256) -> Option { @@ -135,6 +139,7 @@ impl OverlayRecentDB { let mut overlay = MemoryDB::new(); let mut count = 0; let mut latest_era = None; + let mut earliest_era = None; if let Some(val) = db.get(col, &LATEST_ERA_KEY).expect("Low-level database error.") { let mut era = decode::(&val); latest_era = Some(era); @@ -166,6 +171,7 @@ impl OverlayRecentDB { deletions: deletions, }); index += 1; + earliest_era = Some(era); }; if index == 0 || era == 0 { break; @@ -178,9 +184,12 @@ impl OverlayRecentDB { backing_overlay: overlay, pending_overlay: HashMap::default(), journal: journal, - latest_era: latest_era } + latest_era: latest_era, + earliest_era: earliest_era, + } } + } #[inline] @@ -214,6 +223,8 @@ impl JournalDB for OverlayRecentDB { fn latest_era(&self) -> Option { self.journal_overlay.read().latest_era } + fn earliest_era(&self) -> Option { self.journal_overlay.read().earliest_era } + fn state(&self, key: &H256) -> Option { let journal_overlay = self.journal_overlay.read(); let key = to_short_key(key); diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index afa2bb9f46d..7acf20519df 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -32,6 +32,9 @@ pub trait JournalDB: HashDB { /// Check if this database has any commits fn is_empty(&self) -> bool; + /// Get the earliest era in the DB. None if there isn't yet any data in there. + fn earliest_era(&self) -> Option { None } + /// Get the latest era in the DB. None if there isn't yet any data in there. fn latest_era(&self) -> Option; From 8263bd4be239d7a2f5254caedb6c3254af627bad Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 14 Oct 2016 14:45:45 +0200 Subject: [PATCH 09/14] snapshot: single byte for empty accounts (#2625) --- ethcore/src/snapshot/account.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index bc1faea3f5b..30f2cd95677 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -19,12 +19,20 @@ use account_db::{AccountDB, AccountDBMut}; use snapshot::Error; -use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY}; +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}; +// An empty account -- these are replaced with RLP null data for a space optimization. +const ACC_EMPTY: Account = Account { + nonce: U256([0, 0, 0, 0]), + balance: U256([0, 0, 0, 0]), + storage_root: SHA3_NULL_RLP, + code_hash: SHA3_EMPTY, +}; + // whether an encoded account has code and how it is referred to. #[repr(u8)] enum CodeState { @@ -88,6 +96,10 @@ impl Account { // walk the account's storage trie, returning an RLP item containing the // account properties and the storage. pub fn to_fat_rlp(&self, acct_db: &AccountDB, used_code: &mut HashSet) -> Result { + if self == &ACC_EMPTY { + return Ok(::rlp::NULL_RLP.to_vec()); + } + let db = try!(TrieDB::new(acct_db, &self.storage_root)); let mut pairs = Vec::new(); @@ -142,6 +154,11 @@ impl Account { ) -> Result<(Self, Option), Error> { use util::{TrieDBMut, TrieMut}; + // check for special case of empty account. + if rlp.is_empty() { + return Ok((ACC_EMPTY, None)); + } + let nonce = try!(rlp.val_at(0)); let balance = try!(rlp.val_at(1)); let code_state: CodeState = { @@ -214,7 +231,7 @@ mod tests { use std::collections::{HashSet, HashMap}; - use super::Account; + use super::{ACC_EMPTY, Account}; #[test] fn encoding_basic() { @@ -310,4 +327,14 @@ mod tests { assert_eq!(maybe_code, Some(b"this is definitely code".to_vec())); assert_eq!(acc, account1); } + + #[test] + 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)); + } } From 85eeb3ea6e5e21ad8e5644241edf82eb8069f536 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 15 Oct 2016 14:39:15 +0200 Subject: [PATCH 10/14] EIP150.1c (#2591) * EIP150.1b first part. * Add documentation. [ci:skip] * Tweak comment * Fix some tests. * Fix create * Add the new EIP150 test. (#2563) * Fix create some more. * Another fix for create. * Final fixes. * Enable EIP150 test. * Revert the costly suicides to respect EIP150.1b. * Fixups for EIP150.1c * Update tests. * Updating tests * Adding state tests * Updating tests * Updating HF block * Removing flushln [ci:skip] * Commenting out suicide test * New tests. * Switch to EIP tests. * Rename some stuff, combine transition tests. * Fix U256 overflows. * Name cleanups and an effort to fix tests. * Rename back for clarity. * Fix non-EIP-150 OOG CALLs * New transition block number & additional EIP150 tests * Morden transition block set; Tests updated * Added missing test --- ethcore/res/ethereum/classic.json | 3 +- ethcore/res/ethereum/eip150_test.json | 43 + ethcore/res/ethereum/expanse.json | 5 +- ethcore/res/ethereum/frontier.json | 7 +- ethcore/res/ethereum/frontier_like_test.json | 5 +- ethcore/res/ethereum/frontier_test.json | 3 +- ethcore/res/ethereum/homestead_test.json | 3 +- ethcore/res/ethereum/morden.json | 3 +- ethcore/res/ethereum/olympic.json | 4 +- ethcore/res/ethereum/tests | 2 +- ...ardfork_test.json => transition_test.json} | 7 +- ethcore/src/blockchain/blockchain.rs | 5 +- ethcore/src/ethereum/ethash.rs | 19 +- ethcore/src/ethereum/mod.rs | 5 +- ethcore/src/evm/interpreter/gasometer.rs | 111 +- ethcore/src/evm/interpreter/mod.rs | 39 +- ethcore/src/evm/schedule.rs | 62 + ethcore/src/executive.rs | 2 +- ethcore/src/json_tests/chain.rs | 31 +- ethcore/src/json_tests/eip150_state.rs | 43 + ethcore/src/json_tests/homestead_chain.rs | 3 +- ethcore/src/json_tests/mod.rs | 1 + ethcore/src/json_tests/state.rs | 1337 +++++++++-------- ethcore/src/tests/helpers.rs | 7 +- json/src/spec/engine.rs | 2 +- json/src/spec/ethash.rs | 13 +- json/src/spec/params.rs | 2 +- json/src/spec/spec.rs | 4 +- rpc/src/v1/tests/eth.rs | 4 +- 29 files changed, 1023 insertions(+), 752 deletions(-) create mode 100644 ethcore/res/ethereum/eip150_test.json rename ethcore/res/ethereum/{daohardfork_test.json => transition_test.json} (98%) create mode 100644 ethcore/src/json_tests/eip150_state.rs diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index 8feee79e61c..35a2cbed944 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -10,7 +10,8 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0x118c30" + "homesteadTransition": "0x118c30", + "eip150Transition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json new file mode 100644 index 00000000000..39d4b3fe8fd --- /dev/null +++ b/ethcore/res/ethereum/eip150_test.json @@ -0,0 +1,43 @@ +{ + "name": "Homestead (Test)", + "engine": { + "Ethash": { + "params": { + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "homesteadTransition": "0x0", + "eip150Transition": "0x0" + } + } + }, + "params": { + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x1" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x1388" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } + } +} diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index 9b005096b45..d2d036487e3 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -11,10 +11,11 @@ "durationLimit": "0x3C", "blockReward": "0x6f05b59d3b200000", "registrar" : "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21", - "frontierCompatibilityModeLimit": "0x30d40", + "homesteadTransition": "0x30d40", "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", - "bombDefuseTransition": "0x30d40" + "bombDefuseTransition": "0x30d40", + "eip150Transition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 903e87cc7ba..8e92e49b326 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -9,10 +9,10 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0x118c30", + "homesteadTransition": "0x118c30", "daoHardforkTransition": "0x1d4c00", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", - "daoHardforkAccounts": [ + "daoHardforkAccounts": [ "0xd4fe7bc31cedb7bfb8a345f31e668033056b2728", "0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425", "0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f", @@ -129,7 +129,8 @@ "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" - ] + ], + "eip150Transition": "0x259518" } } }, diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index aab48e78eda..99a7ad7128f 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -9,7 +9,7 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0x118c30", + "homesteadTransition": "0x118c30", "daoHardforkTransition": "0x1d4c00", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", "daoHardforkAccounts": [ @@ -129,7 +129,8 @@ "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" - ] + ], + "eip150Transition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 3964d33adf0..1cb3d8cfc03 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -9,7 +9,8 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0xffffffffffffffff" + "homesteadTransition": "0x7fffffffffffffff", + "eip150Transition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index 8a362009ff4..ad64ce2d530 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -9,7 +9,8 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0x0" + "homesteadTransition": "0x0", + "eip150Transition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index ef18df97d6d..fdbe1fec271 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -9,7 +9,8 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d", - "frontierCompatibilityModeLimit": "0x789b0" + "homesteadTransition": "0x789b0", + "eip150Transition": "0x1b34d8" } } }, diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index 99686b07365..ebc7abd4ea2 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -8,7 +8,9 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x08", "blockReward": "0x14D1120D7B160000", - "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050" + "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050", + "homesteadTransition": "0x7fffffffffffffff", + "eip150Transition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index c63dc0e22ea..cd2a6746bb6 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit c63dc0e22eab0c3a40e09a87391e07e103014058 +Subproject commit cd2a6746bb653bf4b1acb6198b40df19ed8dde3b diff --git a/ethcore/res/ethereum/daohardfork_test.json b/ethcore/res/ethereum/transition_test.json similarity index 98% rename from ethcore/res/ethereum/daohardfork_test.json rename to ethcore/res/ethereum/transition_test.json index 90875f4f604..c004bc2ba38 100644 --- a/ethcore/res/ethereum/daohardfork_test.json +++ b/ethcore/res/ethereum/transition_test.json @@ -1,5 +1,5 @@ { - "name": "DAO hard-fork consensus test", + "name": "EIP150.1b hard-fork consensus test", "engine": { "Ethash": { "params": { @@ -9,7 +9,7 @@ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0x5", + "homesteadTransition": "0x5", "daoHardforkTransition": "0x8", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", "daoHardforkAccounts": [ @@ -129,7 +129,8 @@ "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" - ] + ], + "eip150Transition": "0xa" } } }, diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8daf672b917..51be6504397 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -332,7 +332,10 @@ impl BlockProvider for BlockChain { .filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts))) .filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, BodyView::new(b).transaction_hashes()))) .flat_map(|(number, hash, mut receipts, mut hashes)| { - assert_eq!(receipts.len(), hashes.len()); + if receipts.len() != hashes.len() { + warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len()); + assert!(false); + } log_index = receipts.iter().fold(0, |sum, receipt| sum + receipt.logs.len()); let receipts_len = receipts.len(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 982698a5069..e0c18292b0a 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -41,7 +41,7 @@ pub struct EthashParams { /// Namereg contract address. pub registrar: Address, /// Homestead transition block number. - pub frontier_compatibility_mode_limit: u64, + pub homestead_transition: u64, /// DAO hard-fork transition block (X). pub dao_hardfork_transition: u64, /// DAO hard-fork refund contract address (C). @@ -54,6 +54,8 @@ pub struct EthashParams { pub difficulty_hardfork_bound_divisor: U256, /// Block on which there is no additional difficulty from the exponential bomb. pub bomb_defuse_transition: u64, + /// Bad gas transition block number. + pub eip150_transition: u64, } impl From for EthashParams { @@ -66,13 +68,14 @@ impl From for EthashParams { duration_limit: p.duration_limit.into(), block_reward: p.block_reward.into(), registrar: p.registrar.map_or_else(Address::new, Into::into), - frontier_compatibility_mode_limit: p.frontier_compatibility_mode_limit.map_or(0, 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_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_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), + eip150_transition: p.eip150_transition.map_or(0, Into::into), } } } @@ -117,12 +120,14 @@ impl Engine for Ethash { } fn schedule(&self, env_info: &EnvInfo) -> Schedule { - trace!(target: "client", "Creating schedule. fCML={}", self.ethash_params.frontier_compatibility_mode_limit); + trace!(target: "client", "Creating schedule. fCML={}, bGCML={}", self.ethash_params.homestead_transition, self.ethash_params.eip150_transition); - if env_info.number < self.ethash_params.frontier_compatibility_mode_limit { + if env_info.number < self.ethash_params.homestead_transition { Schedule::new_frontier() - } else { + } else if env_info.number < self.ethash_params.eip150_transition { Schedule::new_homestead() + } else { + Schedule::new_homestead_gas_fix() } } @@ -264,7 +269,7 @@ impl Engine for Ethash { } fn verify_transaction_basic(&self, t: &SignedTransaction, header: &Header) -> result::Result<(), Error> { - if header.number() >= self.ethash_params.frontier_compatibility_mode_limit { + if header.number() >= self.ethash_params.homestead_transition { try!(t.check_low_s()); } Ok(()) @@ -290,7 +295,7 @@ impl Ethash { false => self.ethash_params.difficulty_bound_divisor, }; let duration_limit = self.ethash_params.duration_limit; - let frontier_limit = self.ethash_params.frontier_compatibility_mode_limit; + let frontier_limit = self.ethash_params.homestead_transition; let mut target = if header.number() < frontier_limit { if header.timestamp() >= parent.timestamp() + duration_limit { diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 6d4502d2d90..219b3bf5c19 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -51,8 +51,11 @@ pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/fro /// Create a new Homestead chain spec as though it never changed from Frontier. pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/homestead_test.json")) } +/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. +pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) } + /// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. -pub fn new_daohardfork_test() -> Spec { load(include_bytes!("../../res/ethereum/daohardfork_test.json")) } +pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) } /// Create a new Frontier main net chain spec without genesis accounts. pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) } diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index d7022be7ceb..d4c329be05d 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -19,6 +19,7 @@ use super::u256_to_address; use evm::{self, CostType}; use evm::instructions::{self, Instruction, InstructionInfo}; use evm::interpreter::stack::Stack; +use evm::schedule::Schedule; macro_rules! overflowing { ($x: expr) => {{ @@ -31,7 +32,7 @@ macro_rules! overflowing { #[cfg_attr(feature="dev", allow(enum_variant_names))] enum InstructionCost { Gas(Cost), - GasMem(Cost, Cost), + GasMem(Cost, Cost, Option), GasMemCopy(Cost, Cost, Cost) } @@ -56,7 +57,37 @@ impl Gasometer { } } + /// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation + /// and that we `requested` some. + pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option>) -> evm::Result { + match schedule.sub_gas_cap_divisor { + Some(cap_divisor) if self.current_gas >= needed => { + let gas_remaining = self.current_gas - needed; + let max_gas_provided = gas_remaining - gas_remaining / Gas::from(cap_divisor); + if let Some(Ok(r)) = requested { + Ok(min(r, max_gas_provided)) + } else { + Ok(max_gas_provided) + } + }, + _ => { + if let Some(r) = requested { + r + } else if self.current_gas >= needed { + Ok(self.current_gas - needed) + } else { + Ok(0.into()) + } + } + } + } + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + /// Determine how much gas is used by the given instruction, given the machine's state. + /// + /// We guarantee that the final element of the returned tuple (`provided`) will be `Some` + /// iff the `instruction` is one of `CREATE`, or any of the `CALL` variants. In this case, + /// it will be the amount of gas that the current context provides to the child context. pub fn get_gas_cost_mem( &mut self, ext: &evm::Ext, @@ -64,7 +95,7 @@ impl Gasometer { info: &InstructionInfo, stack: &Stack, current_mem_size: usize, - ) -> evm::Result<(Gas, Gas, usize)> { + ) -> evm::Result<(Gas, Gas, usize, Option)> { let schedule = ext.schedule(); let tier = instructions::get_tier_idx(info.tier); let default_gas = Gas::from(schedule.tier_step_gas[tier]); @@ -90,26 +121,42 @@ impl Gasometer { instructions::SLOAD => { InstructionCost::Gas(Gas::from(schedule.sload_gas)) }, + instructions::BALANCE => { + InstructionCost::Gas(Gas::from(schedule.balance_gas)) + }, + instructions::EXTCODESIZE => { + InstructionCost::Gas(Gas::from(schedule.extcodesize_gas)) + }, + instructions::SUICIDE => { + let mut gas = Gas::from(schedule.suicide_gas); + + let address = u256_to_address(stack.peek(0)); + if !ext.exists(&address) { + gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into())); + } + + InstructionCost::Gas(gas) + }, instructions::MSTORE | instructions::MLOAD => { - InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32))) + InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 32)), None) }, instructions::MSTORE8 => { - InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1))) + InstructionCost::GasMem(default_gas, try!(mem_needed_const(stack.peek(0), 1)), None) }, instructions::RETURN => { - InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) + InstructionCost::GasMem(default_gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None) }, instructions::SHA3 => { let w = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(1))), 31)); let words = w >> 5; let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); - InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) + InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None) }, instructions::CALLDATACOPY | instructions::CODECOPY => { InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(0), stack.peek(2))), try!(Gas::from_u256(*stack.peek(2)))) }, instructions::EXTCODECOPY => { - InstructionCost::GasMemCopy(default_gas, try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3)))) + InstructionCost::GasMemCopy(schedule.extcodecopy_base_gas.into(), try!(mem_needed(stack.peek(1), stack.peek(3))), try!(Gas::from_u256(*stack.peek(3)))) }, instructions::LOG0...instructions::LOG4 => { let no_of_topics = instructions::get_log_topics(instruction); @@ -117,10 +164,10 @@ impl Gasometer { let data_gas = overflowing!(try!(Gas::from_u256(*stack.peek(1))).overflow_mul(Gas::from(schedule.log_data_gas))); let gas = overflowing!(data_gas.overflow_add(Gas::from(log_gas))); - InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1)))) + InstructionCost::GasMem(gas, try!(mem_needed(stack.peek(0), stack.peek(1))), None) }, instructions::CALL | instructions::CALLCODE => { - let mut gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas)); + let mut gas = Gas::from(schedule.call_gas); let mem = cmp::max( try!(mem_needed(stack.peek(5), stack.peek(6))), try!(mem_needed(stack.peek(3), stack.peek(4))) @@ -129,27 +176,49 @@ impl Gasometer { let address = u256_to_address(stack.peek(1)); if instruction == instructions::CALL && !ext.exists(&address) { - gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_new_account_gas))); + gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); }; if !stack.peek(2).is_zero() { - gas = overflowing!(gas.overflow_add(Gas::from(schedule.call_value_transfer_gas))); + gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into())); }; - InstructionCost::GasMem(gas,mem) + // TODO: refactor to avoid duplicate calculation here and later on. + let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem)); + let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into())); + let requested = Gas::from_u256(*stack.peek(0)); + let provided = try!(self.gas_provided(schedule, cost_so_far, Some(requested))); + gas = overflowing!(gas.overflow_add(provided)); + + InstructionCost::GasMem(gas, mem, Some(provided)) }, instructions::DELEGATECALL => { - let gas = overflowing!(add_gas_usize(try!(Gas::from_u256(*stack.peek(0))), schedule.call_gas)); + let mut gas = Gas::from(schedule.call_gas); let mem = cmp::max( try!(mem_needed(stack.peek(4), stack.peek(5))), try!(mem_needed(stack.peek(2), stack.peek(3))) ); - InstructionCost::GasMem(gas, mem) + + // TODO: refactor to avoid duplicate calculation here and later on. + let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem)); + let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into())); + let requested = Gas::from_u256(*stack.peek(0)); + let provided = try!(self.gas_provided(schedule, cost_so_far, Some(requested))); + gas = overflowing!(gas.overflow_add(provided)); + + InstructionCost::GasMem(gas, mem, Some(provided)) }, instructions::CREATE => { - let gas = Gas::from(schedule.create_gas); + let mut gas = Gas::from(schedule.create_gas); let mem = try!(mem_needed(stack.peek(1), stack.peek(2))); - InstructionCost::GasMem(gas, mem) + + // TODO: refactor to avoid duplicate calculation here and later on. + let (mem_gas_cost, _, _) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem)); + let cost_so_far = overflowing!(gas.overflow_add(mem_gas_cost.into())); + let provided = try!(self.gas_provided(schedule, cost_so_far, None)); + gas = overflowing!(gas.overflow_add(provided)); + + InstructionCost::GasMem(gas, mem, Some(provided)) }, instructions::EXP => { let expon = stack.peek(1); @@ -157,17 +226,17 @@ impl Gasometer { let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes); InstructionCost::Gas(gas) }, - _ => InstructionCost::Gas(default_gas) + _ => InstructionCost::Gas(default_gas), }; match cost { InstructionCost::Gas(gas) => { - Ok((gas, self.current_mem_gas, 0)) + Ok((gas, self.current_mem_gas, 0, None)) }, - InstructionCost::GasMem(gas, mem_size) => { + InstructionCost::GasMem(gas, mem_size, provided) => { let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); let gas = overflowing!(gas.overflow_add(mem_gas_cost)); - Ok((gas, new_mem_gas, new_mem_size)) + Ok((gas, new_mem_gas, new_mem_size, provided)) }, InstructionCost::GasMemCopy(gas, mem_size, copy) => { let (mem_gas_cost, new_mem_gas, new_mem_size) = try!(self.mem_gas_cost(schedule, current_mem_size, &mem_size)); @@ -175,7 +244,7 @@ impl Gasometer { let copy_gas = Gas::from(schedule.copy_gas) * copy; let gas = overflowing!(gas.overflow_add(copy_gas)); let gas = overflowing!(gas.overflow_add(mem_gas_cost)); - Ok((gas, new_mem_gas, new_mem_size)) + Ok((gas, new_mem_gas, new_mem_size, None)) } } } diff --git a/ethcore/src/evm/interpreter/mod.rs b/ethcore/src/evm/interpreter/mod.rs index 887f37cefd6..51dd8bacdce 100644 --- a/ethcore/src/evm/interpreter/mod.rs +++ b/ethcore/src/evm/interpreter/mod.rs @@ -81,8 +81,6 @@ impl<'a> CodeReader<'a> { enum InstructionResult { Ok, - UseAllGas, - GasLeft(Gas), UnusedGas(Gas), JumpToPosition(U256), // gas left, init_orf, init_size @@ -120,7 +118,7 @@ impl evm::Evm for Interpreter { try!(self.verify_instruction(ext, instruction, info, &stack)); // Calculate gas cost - let (gas_cost, mem_gas, mem_size) = try!(gasometer.get_gas_cost_mem(ext, instruction, info, &stack, self.mem.size())); + let (gas_cost, mem_gas, mem_size, provided) = try!(gasometer.get_gas_cost_mem(ext, instruction, info, &stack, self.mem.size())); // TODO: make compile-time removable if too much of a performance hit. let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &gas_cost.as_u256()); @@ -138,27 +136,21 @@ impl evm::Evm for Interpreter { // Execute instruction let result = try!(self.exec_instruction( - gasometer.current_gas, ¶ms, ext, instruction, &mut reader, &mut stack + gasometer.current_gas, ¶ms, ext, instruction, &mut reader, &mut stack, provided )); evm_debug!({ informant.after_instruction(instruction) }); + if let InstructionResult::UnusedGas(ref gas) = result { + gasometer.current_gas = gasometer.current_gas + *gas; + } + if trace_executed { ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written); } // Advance match result { - InstructionResult::Ok => {}, - InstructionResult::UnusedGas(gas) => { - gasometer.current_gas = gasometer.current_gas + gas; - }, - InstructionResult::UseAllGas => { - gasometer.current_gas = Cost::from(0); - }, - InstructionResult::GasLeft(gas_left) => { - gasometer.current_gas = gas_left; - }, InstructionResult::JumpToPosition(position) => { let pos = try!(self.verify_jump(position, &valid_jump_destinations)); reader.position = pos; @@ -168,6 +160,7 @@ impl evm::Evm for Interpreter { return Ok(GasLeft::NeedsReturn(gas.as_u256(), self.mem.read_slice(off, size))); }, InstructionResult::StopExecution => break, + _ => {}, } } informant.done(); @@ -250,7 +243,8 @@ impl Interpreter { ext: &mut evm::Ext, instruction: Instruction, code: &mut CodeReader, - stack: &mut Stack + stack: &mut Stack, + provided: Option ) -> evm::Result> { match instruction { instructions::JUMP => { @@ -275,31 +269,32 @@ impl Interpreter { let endowment = stack.pop_back(); let init_off = stack.pop_back(); let init_size = stack.pop_back(); + let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed"); let contract_code = self.mem.read_slice(init_off, init_size); let can_create = ext.balance(¶ms.address) >= endowment && ext.depth() < ext.schedule().max_depth; if !can_create { stack.push(U256::zero()); - return Ok(InstructionResult::Ok); + return Ok(InstructionResult::UnusedGas(create_gas)); } - let create_result = ext.create(&gas.as_u256(), &endowment, contract_code); + let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code); return match create_result { ContractCreateResult::Created(address, gas_left) => { stack.push(address_to_u256(address)); - Ok(InstructionResult::GasLeft(Cost::from_u256(gas_left).expect("Gas left cannot be greater."))) + Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater."))) }, ContractCreateResult::Failed => { stack.push(U256::zero()); - // TODO [todr] Should we just StopExecution here? - Ok(InstructionResult::UseAllGas) + Ok(InstructionResult::Ok) } }; }, instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); - let call_gas = Cost::from_u256(stack.pop_back()).expect("Gas is already validated."); + stack.pop_back(); + let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed"); let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); @@ -317,7 +312,7 @@ impl Interpreter { // Add stipend (only CALL|CALLCODE when value > 0) let call_gas = call_gas + value.map_or_else(|| Cost::from(0), |val| match val.is_zero() { false => Cost::from(ext.schedule().call_stipend), - true => Cost::from(0) + true => Cost::from(0), }); // Get sender & receive addresses, check if we have balance diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index e3e4e3b7bff..b8de785b397 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -80,6 +80,19 @@ pub struct Schedule { pub tx_data_non_zero_gas: usize, /// Gas price for copying memory pub copy_gas: usize, + /// Price of EXTCODESIZE + pub extcodesize_gas: usize, + /// Base price of EXTCODECOPY + pub extcodecopy_base_gas: usize, + /// Price of BALANCE + pub balance_gas: usize, + /// Price of SUICIDE + pub suicide_gas: usize, + /// Amount of additional gas to pay when SUICIDE credits a non-existant account + pub suicide_to_new_account_cost: usize, + /// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit. + /// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS + pub sub_gas_cap_divisor: Option, } impl Schedule { @@ -93,6 +106,49 @@ impl Schedule { Self::new(true, true, 53000) } + /// Schedule for the Homestead-era of the Ethereum main net. + pub fn new_homestead_gas_fix() -> Schedule { + Schedule{ + exceptional_failed_code_deposit: true, + have_delegate_call: true, + stack_limit: 1024, + max_depth: 1024, + tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], + exp_gas: 10, + exp_byte_gas: 10, + sha3_gas: 30, + sha3_word_gas: 6, + sload_gas: 200, + sstore_set_gas: 20000, + sstore_reset_gas: 5000, + sstore_refund_gas: 15000, + jumpdest_gas: 1, + log_gas: 375, + log_data_gas: 8, + log_topic_gas: 375, + create_gas: 32000, + call_gas: 700, + call_stipend: 2300, + call_value_transfer_gas: 9000, + call_new_account_gas: 25000, + suicide_refund_gas: 24000, + memory_gas: 3, + quad_coeff_div: 512, + create_data_gas: 200, + tx_gas: 21000, + tx_create_gas: 53000, + tx_data_zero_gas: 4, + tx_data_non_zero_gas: 68, + copy_gas: 3, + extcodesize_gas: 700, + extcodecopy_base_gas: 700, + balance_gas: 400, + suicide_gas: 5000, + suicide_to_new_account_cost: 25000, + sub_gas_cap_divisor: Some(64), + } + } + fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { Schedule{ exceptional_failed_code_deposit: efcd, @@ -126,6 +182,12 @@ impl Schedule { tx_data_zero_gas: 4, tx_data_non_zero_gas: 68, copy_gas: 3, + extcodesize_gas: 20, + extcodecopy_base_gas: 20, + balance_gas: 20, + suicide_gas: 0, + suicide_to_new_account_cost: 0, + sub_gas_cap_divisor: None, } } } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 3c8b6171e3f..54fd902035f 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -697,7 +697,7 @@ mod tests { VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vec_into![29], mem_diff: None, store_diff: None }) }, VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vec_into![3], mem_diff: None, store_diff: None }) }, VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![23], mem_diff: None, store_diff: None }) }, - VMOperation { pc: 39, instruction: 240, gas_cost: 32000.into(), executed: Some(VMExecutedOperation { gas_used: 67979.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 39, instruction: 240, gas_cost: 99979.into(), executed: Some(VMExecutedOperation { gas_used: 64755.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) }, VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vec_into![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) } ], diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 93b0cf82cd7..bf32db1337f 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -48,7 +48,8 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let mut spec = match era { ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Homestead => ethereum::new_homestead_test(), - ChainEra::DaoHardfork => ethereum::new_daohardfork_test(), + ChainEra::Eip150 => ethereum::new_eip150_test(), + ChainEra::TransitionTest => ethereum::new_transition_test(), }; spec.set_genesis_state(state); spec.overwrite_genesis_params(genesis); @@ -116,14 +117,38 @@ mod frontier_era_tests { declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"} } -mod daohardfork_tests { +mod transition_tests { use tests::helpers::*; use super::json_chain_test; fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data, ChainEra::DaoHardfork) + json_chain_test(json_data, ChainEra::TransitionTest) } declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"} declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"} + declare_test!{BlockchainTests_TestNetwork_bcEIP150Test, "BlockchainTests/TestNetwork/bcEIP150Test"} +} + +mod eip150_blockchain_tests { + use tests::helpers::*; + use super::json_chain_test; + + fn do_json_test(json_data: &[u8]) -> Vec { + json_chain_test(json_data, ChainEra::Eip150) + } + + declare_test!{BlockchainTests_EIP150_bcBlockGasLimitTest, "BlockchainTests/EIP150/bcBlockGasLimitTest"} + declare_test!{BlockchainTests_EIP150_bcForkStressTest, "BlockchainTests/EIP150/bcForkStressTest"} + declare_test!{BlockchainTests_EIP150_bcGasPricerTest, "BlockchainTests/EIP150/bcGasPricerTest"} + declare_test!{BlockchainTests_EIP150_bcInvalidHeaderTest, "BlockchainTests/EIP150/bcInvalidHeaderTest"} + declare_test!{BlockchainTests_EIP150_bcInvalidRLPTest, "BlockchainTests/EIP150/bcInvalidRLPTest"} + declare_test!{BlockchainTests_EIP150_bcMultiChainTest, "BlockchainTests/EIP150/bcMultiChainTest"} + declare_test!{BlockchainTests_EIP150_bcRPC_API_Test, "BlockchainTests/EIP150/bcRPC_API_Test"} + declare_test!{BlockchainTests_EIP150_bcStateTest, "BlockchainTests/EIP150/bcStateTest"} + declare_test!{BlockchainTests_EIP150_bcTotalDifficultyTest, "BlockchainTests/EIP150/bcTotalDifficultyTest"} + declare_test!{BlockchainTests_EIP150_bcUncleHeaderValiditiy, "BlockchainTests/EIP150/bcUncleHeaderValiditiy"} + declare_test!{BlockchainTests_EIP150_bcUncleTest, "BlockchainTests/EIP150/bcUncleTest"} + declare_test!{BlockchainTests_EIP150_bcValidBlockTest, "BlockchainTests/EIP150/bcValidBlockTest"} + declare_test!{BlockchainTests_EIP150_bcWalletTest, "BlockchainTests/EIP150/bcWalletTest"} } diff --git a/ethcore/src/json_tests/eip150_state.rs b/ethcore/src/json_tests/eip150_state.rs new file mode 100644 index 00000000000..9076286eb46 --- /dev/null +++ b/ethcore/src/json_tests/eip150_state.rs @@ -0,0 +1,43 @@ +// 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 . + +use super::test_common::*; +use tests::helpers::*; +use super::state::json_chain_test; + +fn do_json_test(json_data: &[u8]) -> Vec { + json_chain_test(json_data, ChainEra::Eip150) +} + +declare_test!{StateTests_EIP150_stEIPSpecificTest, "StateTests/EIP150/stEIPSpecificTest"} +declare_test!{StateTests_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP150/stEIPsingleCodeGasPrices"} +declare_test!{StateTests_EIP150_stMemExpandingEIPCalls, "StateTests/EIP150/stMemExpandingEIPCalls"} + +declare_test!{StateTests_EIP150_stCallCodes, "StateTests/EIP150/Homestead/stCallCodes"} +declare_test!{StateTests_EIP150_stCallCreateCallCodeTest, "StateTests/EIP150/Homestead/stCallCreateCallCodeTest"} +declare_test!{StateTests_EIP150_stDelegatecallTest, "StateTests/EIP150/Homestead/stDelegatecallTest"} +declare_test!{StateTests_EIP150_stInitCodeTest, "StateTests/EIP150/Homestead/stInitCodeTest"} +declare_test!{StateTests_EIP150_stLogTests, "StateTests/EIP150/Homestead/stLogTests"} +declare_test!{heavy => StateTests_EIP150_stMemoryStressTest, "StateTests/EIP150/Homestead/stMemoryStressTest"} +declare_test!{heavy => StateTests_EIP150_stMemoryTest, "StateTests/EIP150/Homestead/stMemoryTest"} +declare_test!{StateTests_EIP150_stPreCompiledContracts, "StateTests/EIP150/Homestead/stPreCompiledContracts"} +declare_test!{heavy => StateTests_EIP150_stQuadraticComplexityTest, "StateTests/EIP150/Homestead/stQuadraticComplexityTest"} +declare_test!{StateTests_EIP150_stRecursiveCreate, "StateTests/EIP150/Homestead/stRecursiveCreate"} +declare_test!{StateTests_EIP150_stRefundTest, "StateTests/EIP150/Homestead/stRefundTest"} +declare_test!{StateTests_EIP150_stSpecialTest, "StateTests/EIP150/Homestead/stSpecialTest"} +declare_test!{StateTests_EIP150_stSystemOperationsTest, "StateTests/EIP150/Homestead/stSystemOperationsTest"} +declare_test!{StateTests_EIP150_stTransactionTest, "StateTests/EIP150/Homestead/stTransactionTest"} +declare_test!{StateTests_EIP150_stWalletTest, "StateTests/EIP150/Homestead/stWalletTest"} diff --git a/ethcore/src/json_tests/homestead_chain.rs b/ethcore/src/json_tests/homestead_chain.rs index 37a9d0a21a1..d92b8a7f1aa 100644 --- a/ethcore/src/json_tests/homestead_chain.rs +++ b/ethcore/src/json_tests/homestead_chain.rs @@ -37,5 +37,6 @@ declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/ declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"} declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"} declare_test!{BlockchainTests_Homestead_bcShanghaiLove, "BlockchainTests/Homestead/bcShanghaiLove"} -declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"} +// TODO [ToDr] uncomment as soon as eip150 tests are merged to develop branch of ethereum/tests +// declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"} declare_test!{BlockchainTests_Homestead_bcExploitTest, "BlockchainTests/Homestead/bcExploitTest"} diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index 841db229ee6..7a5dd30d249 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -23,4 +23,5 @@ mod state; mod chain; mod homestead_state; mod homestead_chain; +mod eip150_state; mod trie; diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index d7011cd28c2..16e532401b4 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -20,10 +20,6 @@ use pod_state::{self, PodState}; use ethereum; use ethjson; -fn do_json_test(json_data: &[u8]) -> Vec { - json_chain_test(json_data, ChainEra::Frontier) -} - pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); let tests = ethjson::state::Test::load(json_data).unwrap(); @@ -31,8 +27,9 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let engine = match era { ChainEra::Frontier => ethereum::new_mainnet_like().engine, ChainEra::Homestead => ethereum::new_homestead_test().engine, - ChainEra::DaoHardfork => ethereum::new_daohardfork_test().engine, -}; + ChainEra::Eip150 => ethereum::new_eip150_test().engine, + ChainEra::TransitionTest => ethereum::new_transition_test().engine, + }; for (name, test) in tests.into_iter() { let mut fail = false; @@ -93,665 +90,673 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { failed } -declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} -declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} -declare_test!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} -declare_test!{StateTests_stExample, "StateTests/stExample"} -declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"} -declare_test!{StateTests_stLogTests, "StateTests/stLogTests"} -declare_test!{heavy => StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"} -declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"} -declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"} -declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} -declare_test!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} -declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} -declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} -declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} -declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} -declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} -declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} -declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} +mod frontier_tests { + use super::json_chain_test; + use tests::helpers::ChainEra; + fn do_json_test(json_data: &[u8]) -> Vec { + json_chain_test(json_data, ChainEra::Frontier) + } -declare_test!{StateTests_RandomTests_st201503121803PYTHON, "StateTests/RandomTests/st201503121803PYTHON"} -declare_test!{StateTests_RandomTests_st201503121806PYTHON, "StateTests/RandomTests/st201503121806PYTHON"} -declare_test!{StateTests_RandomTests_st201503121848GO, "StateTests/RandomTests/st201503121848GO"} -declare_test!{StateTests_RandomTests_st201503121849GO, "StateTests/RandomTests/st201503121849GO"} -declare_test!{StateTests_RandomTests_st201503121850GO, "StateTests/RandomTests/st201503121850GO"} -declare_test!{StateTests_RandomTests_st201503121851GO, "StateTests/RandomTests/st201503121851GO"} -declare_test!{StateTests_RandomTests_st201503121953GO, "StateTests/RandomTests/st201503121953GO"} -declare_test!{StateTests_RandomTests_st201503122023GO, "StateTests/RandomTests/st201503122023GO"} -declare_test!{StateTests_RandomTests_st201503122023PYTHON, "StateTests/RandomTests/st201503122023PYTHON"} -declare_test!{StateTests_RandomTests_st201503122027GO, "StateTests/RandomTests/st201503122027GO"} -declare_test!{StateTests_RandomTests_st201503122054GO, "StateTests/RandomTests/st201503122054GO"} -declare_test!{StateTests_RandomTests_st201503122055GO, "StateTests/RandomTests/st201503122055GO"} -declare_test!{StateTests_RandomTests_st201503122115CPPJIT, "StateTests/RandomTests/st201503122115CPPJIT"} -declare_test!{StateTests_RandomTests_st201503122115GO, "StateTests/RandomTests/st201503122115GO"} -declare_test!{StateTests_RandomTests_st201503122123GO, "StateTests/RandomTests/st201503122123GO"} -declare_test!{StateTests_RandomTests_st201503122124GO, "StateTests/RandomTests/st201503122124GO"} -declare_test!{StateTests_RandomTests_st201503122128PYTHON, "StateTests/RandomTests/st201503122128PYTHON"} -declare_test!{StateTests_RandomTests_st201503122140GO, "StateTests/RandomTests/st201503122140GO"} -declare_test!{StateTests_RandomTests_st201503122159GO, "StateTests/RandomTests/st201503122159GO"} -declare_test!{StateTests_RandomTests_st201503122204GO, "StateTests/RandomTests/st201503122204GO"} -declare_test!{StateTests_RandomTests_st201503122212GO, "StateTests/RandomTests/st201503122212GO"} -declare_test!{StateTests_RandomTests_st201503122231GO, "StateTests/RandomTests/st201503122231GO"} -declare_test!{StateTests_RandomTests_st201503122238GO, "StateTests/RandomTests/st201503122238GO"} -declare_test!{StateTests_RandomTests_st201503122252GO, "StateTests/RandomTests/st201503122252GO"} -declare_test!{StateTests_RandomTests_st201503122316GO, "StateTests/RandomTests/st201503122316GO"} -declare_test!{StateTests_RandomTests_st201503122324GO, "StateTests/RandomTests/st201503122324GO"} -declare_test!{StateTests_RandomTests_st201503122358GO, "StateTests/RandomTests/st201503122358GO"} -declare_test!{StateTests_RandomTests_st201503130002GO, "StateTests/RandomTests/st201503130002GO"} -declare_test!{StateTests_RandomTests_st201503130005GO, "StateTests/RandomTests/st201503130005GO"} -declare_test!{StateTests_RandomTests_st201503130007GO, "StateTests/RandomTests/st201503130007GO"} -declare_test!{StateTests_RandomTests_st201503130010GO, "StateTests/RandomTests/st201503130010GO"} -declare_test!{StateTests_RandomTests_st201503130023PYTHON, "StateTests/RandomTests/st201503130023PYTHON"} -declare_test!{StateTests_RandomTests_st201503130059GO, "StateTests/RandomTests/st201503130059GO"} -declare_test!{StateTests_RandomTests_st201503130101GO, "StateTests/RandomTests/st201503130101GO"} -declare_test!{StateTests_RandomTests_st201503130109GO, "StateTests/RandomTests/st201503130109GO"} -declare_test!{StateTests_RandomTests_st201503130117GO, "StateTests/RandomTests/st201503130117GO"} -declare_test!{StateTests_RandomTests_st201503130122GO, "StateTests/RandomTests/st201503130122GO"} -declare_test!{StateTests_RandomTests_st201503130156GO, "StateTests/RandomTests/st201503130156GO"} -declare_test!{StateTests_RandomTests_st201503130156PYTHON, "StateTests/RandomTests/st201503130156PYTHON"} -declare_test!{StateTests_RandomTests_st201503130207GO, "StateTests/RandomTests/st201503130207GO"} -declare_test!{StateTests_RandomTests_st201503130219CPPJIT, "StateTests/RandomTests/st201503130219CPPJIT"} -declare_test!{StateTests_RandomTests_st201503130219GO, "StateTests/RandomTests/st201503130219GO"} -declare_test!{StateTests_RandomTests_st201503130243GO, "StateTests/RandomTests/st201503130243GO"} -declare_test!{StateTests_RandomTests_st201503130246GO, "StateTests/RandomTests/st201503130246GO"} -declare_test!{StateTests_RandomTests_st201503130321GO, "StateTests/RandomTests/st201503130321GO"} -declare_test!{StateTests_RandomTests_st201503130322GO, "StateTests/RandomTests/st201503130322GO"} -declare_test!{StateTests_RandomTests_st201503130332GO, "StateTests/RandomTests/st201503130332GO"} -declare_test!{StateTests_RandomTests_st201503130359GO, "StateTests/RandomTests/st201503130359GO"} -declare_test!{StateTests_RandomTests_st201503130405GO, "StateTests/RandomTests/st201503130405GO"} -declare_test!{StateTests_RandomTests_st201503130408GO, "StateTests/RandomTests/st201503130408GO"} -declare_test!{StateTests_RandomTests_st201503130411GO, "StateTests/RandomTests/st201503130411GO"} -declare_test!{StateTests_RandomTests_st201503130431GO, "StateTests/RandomTests/st201503130431GO"} -declare_test!{StateTests_RandomTests_st201503130437GO, "StateTests/RandomTests/st201503130437GO"} -declare_test!{StateTests_RandomTests_st201503130450GO, "StateTests/RandomTests/st201503130450GO"} -declare_test!{StateTests_RandomTests_st201503130512CPPJIT, "StateTests/RandomTests/st201503130512CPPJIT"} -declare_test!{StateTests_RandomTests_st201503130512GO, "StateTests/RandomTests/st201503130512GO"} -declare_test!{StateTests_RandomTests_st201503130615GO, "StateTests/RandomTests/st201503130615GO"} -declare_test!{StateTests_RandomTests_st201503130705GO, "StateTests/RandomTests/st201503130705GO"} -declare_test!{StateTests_RandomTests_st201503130733CPPJIT, "StateTests/RandomTests/st201503130733CPPJIT"} -declare_test!{StateTests_RandomTests_st201503130733GO, "StateTests/RandomTests/st201503130733GO"} -declare_test!{StateTests_RandomTests_st201503130747GO, "StateTests/RandomTests/st201503130747GO"} -declare_test!{StateTests_RandomTests_st201503130751GO, "StateTests/RandomTests/st201503130751GO"} -declare_test!{StateTests_RandomTests_st201503130752PYTHON, "StateTests/RandomTests/st201503130752PYTHON"} -declare_test!{StateTests_RandomTests_st201503130757PYTHON, "StateTests/RandomTests/st201503130757PYTHON"} -declare_test!{StateTests_RandomTests_st201503131658GO, "StateTests/RandomTests/st201503131658GO"} -declare_test!{StateTests_RandomTests_st201503131739GO, "StateTests/RandomTests/st201503131739GO"} -declare_test!{StateTests_RandomTests_st201503131755CPPJIT, "StateTests/RandomTests/st201503131755CPPJIT"} -declare_test!{StateTests_RandomTests_st201503131755GO, "StateTests/RandomTests/st201503131755GO"} -declare_test!{StateTests_RandomTests_st201503132001CPPJIT, "StateTests/RandomTests/st201503132001CPPJIT"} -declare_test!{StateTests_RandomTests_st201503132127PYTHON, "StateTests/RandomTests/st201503132127PYTHON"} -declare_test!{StateTests_RandomTests_st201503132201CPPJIT, "StateTests/RandomTests/st201503132201CPPJIT"} -declare_test!{StateTests_RandomTests_st201503132201GO, "StateTests/RandomTests/st201503132201GO"} -declare_test!{StateTests_RandomTests_st201503132202PYTHON, "StateTests/RandomTests/st201503132202PYTHON"} -declare_test!{StateTests_RandomTests_st201503140002PYTHON, "StateTests/RandomTests/st201503140002PYTHON"} -declare_test!{StateTests_RandomTests_st201503140240PYTHON, "StateTests/RandomTests/st201503140240PYTHON"} -declare_test!{StateTests_RandomTests_st201503140522PYTHON, "StateTests/RandomTests/st201503140522PYTHON"} -declare_test!{StateTests_RandomTests_st201503140756PYTHON, "StateTests/RandomTests/st201503140756PYTHON"} -declare_test!{StateTests_RandomTests_st201503141144PYTHON, "StateTests/RandomTests/st201503141144PYTHON"} -declare_test!{StateTests_RandomTests_st201503141510PYTHON, "StateTests/RandomTests/st201503141510PYTHON"} -declare_test!{StateTests_RandomTests_st201503150427PYTHON, "StateTests/RandomTests/st201503150427PYTHON"} -declare_test!{StateTests_RandomTests_st201503150716PYTHON, "StateTests/RandomTests/st201503150716PYTHON"} -declare_test!{StateTests_RandomTests_st201503151450PYTHON, "StateTests/RandomTests/st201503151450PYTHON"} -declare_test!{StateTests_RandomTests_st201503151516PYTHON, "StateTests/RandomTests/st201503151516PYTHON"} -declare_test!{StateTests_RandomTests_st201503151753PYTHON, "StateTests/RandomTests/st201503151753PYTHON"} -declare_test!{StateTests_RandomTests_st201503152057PYTHON, "StateTests/RandomTests/st201503152057PYTHON"} -declare_test!{StateTests_RandomTests_st201503152241PYTHON, "StateTests/RandomTests/st201503152241PYTHON"} -declare_test!{StateTests_RandomTests_st201503160014PYTHON, "StateTests/RandomTests/st201503160014PYTHON"} -declare_test!{StateTests_RandomTests_st201503160733PYTHON, "StateTests/RandomTests/st201503160733PYTHON"} -declare_test!{StateTests_RandomTests_st201503170051PYTHON, "StateTests/RandomTests/st201503170051PYTHON"} -declare_test!{StateTests_RandomTests_st201503170433PYTHON, "StateTests/RandomTests/st201503170433PYTHON"} -declare_test!{StateTests_RandomTests_st201503170523PYTHON, "StateTests/RandomTests/st201503170523PYTHON"} -declare_test!{StateTests_RandomTests_st201503171108PYTHON, "StateTests/RandomTests/st201503171108PYTHON"} -declare_test!{StateTests_RandomTests_st201503181223GO, "StateTests/RandomTests/st201503181223GO"} -declare_test!{StateTests_RandomTests_st201503181225GO, "StateTests/RandomTests/st201503181225GO"} -declare_test!{StateTests_RandomTests_st201503181226CPPJIT, "StateTests/RandomTests/st201503181226CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181227CPPJIT, "StateTests/RandomTests/st201503181227CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181227GO, "StateTests/RandomTests/st201503181227GO"} -declare_test!{StateTests_RandomTests_st201503181229GO, "StateTests/RandomTests/st201503181229GO"} -declare_test!{StateTests_RandomTests_st201503181230CPPJIT, "StateTests/RandomTests/st201503181230CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181230GO, "StateTests/RandomTests/st201503181230GO"} -declare_test!{StateTests_RandomTests_st201503181231GO, "StateTests/RandomTests/st201503181231GO"} -declare_test!{StateTests_RandomTests_st201503181232CPPJIT, "StateTests/RandomTests/st201503181232CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181232GO, "StateTests/RandomTests/st201503181232GO"} -declare_test!{StateTests_RandomTests_st201503181233GO, "StateTests/RandomTests/st201503181233GO"} -declare_test!{StateTests_RandomTests_st201503181234CPPJIT, "StateTests/RandomTests/st201503181234CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181234GO, "StateTests/RandomTests/st201503181234GO"} -declare_test!{StateTests_RandomTests_st201503181235CPPJIT, "StateTests/RandomTests/st201503181235CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181235GO, "StateTests/RandomTests/st201503181235GO"} -declare_test!{StateTests_RandomTests_st201503181236GO, "StateTests/RandomTests/st201503181236GO"} -declare_test!{StateTests_RandomTests_st201503181237GO, "StateTests/RandomTests/st201503181237GO"} -declare_test!{StateTests_RandomTests_st201503181239GO, "StateTests/RandomTests/st201503181239GO"} -declare_test!{StateTests_RandomTests_st201503181241CPPJIT, "StateTests/RandomTests/st201503181241CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181241GO, "StateTests/RandomTests/st201503181241GO"} -declare_test!{StateTests_RandomTests_st201503181243GO, "StateTests/RandomTests/st201503181243GO"} -declare_test!{StateTests_RandomTests_st201503181244GO, "StateTests/RandomTests/st201503181244GO"} -declare_test!{StateTests_RandomTests_st201503181245CPPJIT, "StateTests/RandomTests/st201503181245CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181245GO, "StateTests/RandomTests/st201503181245GO"} -declare_test!{StateTests_RandomTests_st201503181246CPPJIT, "StateTests/RandomTests/st201503181246CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181246GO, "StateTests/RandomTests/st201503181246GO"} -declare_test!{StateTests_RandomTests_st201503181247GO, "StateTests/RandomTests/st201503181247GO"} -declare_test!{StateTests_RandomTests_st201503181248GO, "StateTests/RandomTests/st201503181248GO"} -declare_test!{StateTests_RandomTests_st201503181249GO, "StateTests/RandomTests/st201503181249GO"} -declare_test!{StateTests_RandomTests_st201503181250CPPJIT, "StateTests/RandomTests/st201503181250CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181250GO, "StateTests/RandomTests/st201503181250GO"} -declare_test!{StateTests_RandomTests_st201503181251GO, "StateTests/RandomTests/st201503181251GO"} -declare_test!{StateTests_RandomTests_st201503181252CPPJIT, "StateTests/RandomTests/st201503181252CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181253GO, "StateTests/RandomTests/st201503181253GO"} -declare_test!{StateTests_RandomTests_st201503181255CPPJIT, "StateTests/RandomTests/st201503181255CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181255GO, "StateTests/RandomTests/st201503181255GO"} -declare_test!{StateTests_RandomTests_st201503181257GO, "StateTests/RandomTests/st201503181257GO"} -declare_test!{StateTests_RandomTests_st201503181258CPPJIT, "StateTests/RandomTests/st201503181258CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181258GO, "StateTests/RandomTests/st201503181258GO"} -declare_test!{StateTests_RandomTests_st201503181301CPPJIT, "StateTests/RandomTests/st201503181301CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181301GO, "StateTests/RandomTests/st201503181301GO"} -declare_test!{StateTests_RandomTests_st201503181303GO, "StateTests/RandomTests/st201503181303GO"} -declare_test!{StateTests_RandomTests_st201503181304GO, "StateTests/RandomTests/st201503181304GO"} -declare_test!{StateTests_RandomTests_st201503181305GO, "StateTests/RandomTests/st201503181305GO"} -declare_test!{StateTests_RandomTests_st201503181306GO, "StateTests/RandomTests/st201503181306GO"} -declare_test!{StateTests_RandomTests_st201503181307CPPJIT, "StateTests/RandomTests/st201503181307CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181307GO, "StateTests/RandomTests/st201503181307GO"} -declare_test!{StateTests_RandomTests_st201503181308GO, "StateTests/RandomTests/st201503181308GO"} -declare_test!{StateTests_RandomTests_st201503181309GO, "StateTests/RandomTests/st201503181309GO"} -declare_test!{StateTests_RandomTests_st201503181310GO, "StateTests/RandomTests/st201503181310GO"} -declare_test!{StateTests_RandomTests_st201503181311GO, "StateTests/RandomTests/st201503181311GO"} -declare_test!{StateTests_RandomTests_st201503181313GO, "StateTests/RandomTests/st201503181313GO"} -declare_test!{StateTests_RandomTests_st201503181314GO, "StateTests/RandomTests/st201503181314GO"} -declare_test!{StateTests_RandomTests_st201503181315CPPJIT, "StateTests/RandomTests/st201503181315CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181315GO, "StateTests/RandomTests/st201503181315GO"} -declare_test!{StateTests_RandomTests_st201503181316CPPJIT, "StateTests/RandomTests/st201503181316CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181316PYTHON, "StateTests/RandomTests/st201503181316PYTHON"} -declare_test!{StateTests_RandomTests_st201503181317GO, "StateTests/RandomTests/st201503181317GO"} -declare_test!{StateTests_RandomTests_st201503181318CPPJIT, "StateTests/RandomTests/st201503181318CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181318GO, "StateTests/RandomTests/st201503181318GO"} -declare_test!{StateTests_RandomTests_st201503181319GO, "StateTests/RandomTests/st201503181319GO"} -declare_test!{StateTests_RandomTests_st201503181319PYTHON, "StateTests/RandomTests/st201503181319PYTHON"} -declare_test!{StateTests_RandomTests_st201503181322GO, "StateTests/RandomTests/st201503181322GO"} -declare_test!{StateTests_RandomTests_st201503181323CPPJIT, "StateTests/RandomTests/st201503181323CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181323GO, "StateTests/RandomTests/st201503181323GO"} -declare_test!{StateTests_RandomTests_st201503181324GO, "StateTests/RandomTests/st201503181324GO"} -declare_test!{StateTests_RandomTests_st201503181325GO, "StateTests/RandomTests/st201503181325GO"} -declare_test!{StateTests_RandomTests_st201503181326CPPJIT, "StateTests/RandomTests/st201503181326CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181326GO, "StateTests/RandomTests/st201503181326GO"} -declare_test!{StateTests_RandomTests_st201503181327GO, "StateTests/RandomTests/st201503181327GO"} -declare_test!{StateTests_RandomTests_st201503181329CPPJIT, "StateTests/RandomTests/st201503181329CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181329GO, "StateTests/RandomTests/st201503181329GO"} -declare_test!{StateTests_RandomTests_st201503181330GO, "StateTests/RandomTests/st201503181330GO"} -declare_test!{StateTests_RandomTests_st201503181332GO, "StateTests/RandomTests/st201503181332GO"} -declare_test!{StateTests_RandomTests_st201503181333GO, "StateTests/RandomTests/st201503181333GO"} -declare_test!{StateTests_RandomTests_st201503181334GO, "StateTests/RandomTests/st201503181334GO"} -declare_test!{StateTests_RandomTests_st201503181336CPPJIT, "StateTests/RandomTests/st201503181336CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181337GO, "StateTests/RandomTests/st201503181337GO"} -declare_test!{StateTests_RandomTests_st201503181338GO, "StateTests/RandomTests/st201503181338GO"} -declare_test!{StateTests_RandomTests_st201503181339CPPJIT, "StateTests/RandomTests/st201503181339CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181339GO, "StateTests/RandomTests/st201503181339GO"} -declare_test!{StateTests_RandomTests_st201503181340GO, "StateTests/RandomTests/st201503181340GO"} -declare_test!{StateTests_RandomTests_st201503181341CPPJIT, "StateTests/RandomTests/st201503181341CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181342CPPJIT, "StateTests/RandomTests/st201503181342CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181342GO, "StateTests/RandomTests/st201503181342GO"} -declare_test!{StateTests_RandomTests_st201503181345GO, "StateTests/RandomTests/st201503181345GO"} -declare_test!{StateTests_RandomTests_st201503181346GO, "StateTests/RandomTests/st201503181346GO"} -declare_test!{StateTests_RandomTests_st201503181347CPPJIT, "StateTests/RandomTests/st201503181347CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181347GO, "StateTests/RandomTests/st201503181347GO"} -declare_test!{StateTests_RandomTests_st201503181347PYTHON, "StateTests/RandomTests/st201503181347PYTHON"} -declare_test!{StateTests_RandomTests_st201503181350CPPJIT, "StateTests/RandomTests/st201503181350CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181352GO, "StateTests/RandomTests/st201503181352GO"} -declare_test!{StateTests_RandomTests_st201503181353GO, "StateTests/RandomTests/st201503181353GO"} -declare_test!{StateTests_RandomTests_st201503181354CPPJIT, "StateTests/RandomTests/st201503181354CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181354GO, "StateTests/RandomTests/st201503181354GO"} -declare_test!{StateTests_RandomTests_st201503181355GO, "StateTests/RandomTests/st201503181355GO"} -declare_test!{StateTests_RandomTests_st201503181356CPPJIT, "StateTests/RandomTests/st201503181356CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181357CPPJIT, "StateTests/RandomTests/st201503181357CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181358CPPJIT, "StateTests/RandomTests/st201503181358CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181358GO, "StateTests/RandomTests/st201503181358GO"} -declare_test!{StateTests_RandomTests_st201503181359GO, "StateTests/RandomTests/st201503181359GO"} -declare_test!{StateTests_RandomTests_st201503181402CPPJIT, "StateTests/RandomTests/st201503181402CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181403GO, "StateTests/RandomTests/st201503181403GO"} -declare_test!{StateTests_RandomTests_st201503181406CPPJIT, "StateTests/RandomTests/st201503181406CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181406GO, "StateTests/RandomTests/st201503181406GO"} -declare_test!{StateTests_RandomTests_st201503181410GO, "StateTests/RandomTests/st201503181410GO"} -declare_test!{StateTests_RandomTests_st201503181412CPPJIT, "StateTests/RandomTests/st201503181412CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181413GO, "StateTests/RandomTests/st201503181413GO"} -declare_test!{StateTests_RandomTests_st201503181415GO, "StateTests/RandomTests/st201503181415GO"} -declare_test!{StateTests_RandomTests_st201503181416GO, "StateTests/RandomTests/st201503181416GO"} -declare_test!{StateTests_RandomTests_st201503181417CPPJIT, "StateTests/RandomTests/st201503181417CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181417GO, "StateTests/RandomTests/st201503181417GO"} -declare_test!{StateTests_RandomTests_st201503181418CPPJIT, "StateTests/RandomTests/st201503181418CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181422GO, "StateTests/RandomTests/st201503181422GO"} -declare_test!{StateTests_RandomTests_st201503181423CPPJIT, "StateTests/RandomTests/st201503181423CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181424GO, "StateTests/RandomTests/st201503181424GO"} -declare_test!{StateTests_RandomTests_st201503181426CPPJIT, "StateTests/RandomTests/st201503181426CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181426GO, "StateTests/RandomTests/st201503181426GO"} -declare_test!{StateTests_RandomTests_st201503181428GO, "StateTests/RandomTests/st201503181428GO"} -declare_test!{StateTests_RandomTests_st201503181430CPPJIT, "StateTests/RandomTests/st201503181430CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181435GO, "StateTests/RandomTests/st201503181435GO"} -declare_test!{StateTests_RandomTests_st201503181436GO, "StateTests/RandomTests/st201503181436GO"} -declare_test!{StateTests_RandomTests_st201503181437CPPJIT, "StateTests/RandomTests/st201503181437CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181437GO, "StateTests/RandomTests/st201503181437GO"} -declare_test!{StateTests_RandomTests_st201503181438CPPJIT, "StateTests/RandomTests/st201503181438CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181438GO, "StateTests/RandomTests/st201503181438GO"} -declare_test!{StateTests_RandomTests_st201503181439CPPJIT, "StateTests/RandomTests/st201503181439CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181439GO, "StateTests/RandomTests/st201503181439GO"} -declare_test!{StateTests_RandomTests_st201503181439PYTHON, "StateTests/RandomTests/st201503181439PYTHON"} -declare_test!{StateTests_RandomTests_st201503181440GO, "StateTests/RandomTests/st201503181440GO"} -declare_test!{StateTests_RandomTests_st201503181441GO, "StateTests/RandomTests/st201503181441GO"} -declare_test!{StateTests_RandomTests_st201503181442GO, "StateTests/RandomTests/st201503181442GO"} -declare_test!{StateTests_RandomTests_st201503181445CPPJIT, "StateTests/RandomTests/st201503181445CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181446GO, "StateTests/RandomTests/st201503181446GO"} -declare_test!{StateTests_RandomTests_st201503181447GO, "StateTests/RandomTests/st201503181447GO"} -declare_test!{StateTests_RandomTests_st201503181450GO, "StateTests/RandomTests/st201503181450GO"} -declare_test!{StateTests_RandomTests_st201503181451CPPJIT, "StateTests/RandomTests/st201503181451CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181453GO, "StateTests/RandomTests/st201503181453GO"} -declare_test!{StateTests_RandomTests_st201503181455GO, "StateTests/RandomTests/st201503181455GO"} -declare_test!{StateTests_RandomTests_st201503181456CPPJIT, "StateTests/RandomTests/st201503181456CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181457GO, "StateTests/RandomTests/st201503181457GO"} -declare_test!{StateTests_RandomTests_st201503181458GO, "StateTests/RandomTests/st201503181458GO"} -declare_test!{StateTests_RandomTests_st201503181459GO, "StateTests/RandomTests/st201503181459GO"} -declare_test!{StateTests_RandomTests_st201503181500GO, "StateTests/RandomTests/st201503181500GO"} -declare_test!{StateTests_RandomTests_st201503181501GO, "StateTests/RandomTests/st201503181501GO"} -declare_test!{StateTests_RandomTests_st201503181503GO, "StateTests/RandomTests/st201503181503GO"} -declare_test!{StateTests_RandomTests_st201503181504GO, "StateTests/RandomTests/st201503181504GO"} -declare_test!{StateTests_RandomTests_st201503181505GO, "StateTests/RandomTests/st201503181505GO"} -declare_test!{StateTests_RandomTests_st201503181506CPPJIT, "StateTests/RandomTests/st201503181506CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181507GO, "StateTests/RandomTests/st201503181507GO"} -declare_test!{StateTests_RandomTests_st201503181509CPPJIT, "StateTests/RandomTests/st201503181509CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181509GO, "StateTests/RandomTests/st201503181509GO"} -declare_test!{StateTests_RandomTests_st201503181510GO, "StateTests/RandomTests/st201503181510GO"} -declare_test!{StateTests_RandomTests_st201503181511GO, "StateTests/RandomTests/st201503181511GO"} -declare_test!{StateTests_RandomTests_st201503181512GO, "StateTests/RandomTests/st201503181512GO"} -declare_test!{StateTests_RandomTests_st201503181513CPPJIT, "StateTests/RandomTests/st201503181513CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181513GO, "StateTests/RandomTests/st201503181513GO"} -declare_test!{StateTests_RandomTests_st201503181514CPPJIT, "StateTests/RandomTests/st201503181514CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181514GO, "StateTests/RandomTests/st201503181514GO"} -declare_test!{StateTests_RandomTests_st201503181517CPPJIT, "StateTests/RandomTests/st201503181517CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181517GO, "StateTests/RandomTests/st201503181517GO"} -declare_test!{StateTests_RandomTests_st201503181519CPPJIT, "StateTests/RandomTests/st201503181519CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181519GO, "StateTests/RandomTests/st201503181519GO"} -declare_test!{StateTests_RandomTests_st201503181520CPPJIT, "StateTests/RandomTests/st201503181520CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181520GO, "StateTests/RandomTests/st201503181520GO"} -declare_test!{StateTests_RandomTests_st201503181521GO, "StateTests/RandomTests/st201503181521GO"} -declare_test!{StateTests_RandomTests_st201503181522GO, "StateTests/RandomTests/st201503181522GO"} -declare_test!{StateTests_RandomTests_st201503181524CPPJIT, "StateTests/RandomTests/st201503181524CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181524GO, "StateTests/RandomTests/st201503181524GO"} -declare_test!{StateTests_RandomTests_st201503181526GO, "StateTests/RandomTests/st201503181526GO"} -declare_test!{StateTests_RandomTests_st201503181527GO, "StateTests/RandomTests/st201503181527GO"} -declare_test!{StateTests_RandomTests_st201503181528CPPJIT, "StateTests/RandomTests/st201503181528CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181528GO, "StateTests/RandomTests/st201503181528GO"} -declare_test!{StateTests_RandomTests_st201503181528PYTHON, "StateTests/RandomTests/st201503181528PYTHON"} -declare_test!{StateTests_RandomTests_st201503181529GO, "StateTests/RandomTests/st201503181529GO"} -declare_test!{StateTests_RandomTests_st201503181531CPPJIT, "StateTests/RandomTests/st201503181531CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181533GO, "StateTests/RandomTests/st201503181533GO"} -declare_test!{StateTests_RandomTests_st201503181534CPPJIT, "StateTests/RandomTests/st201503181534CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181534GO, "StateTests/RandomTests/st201503181534GO"} -declare_test!{StateTests_RandomTests_st201503181536CPPJIT, "StateTests/RandomTests/st201503181536CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181536GO, "StateTests/RandomTests/st201503181536GO"} -declare_test!{StateTests_RandomTests_st201503181537GO, "StateTests/RandomTests/st201503181537GO"} -declare_test!{StateTests_RandomTests_st201503181538GO, "StateTests/RandomTests/st201503181538GO"} -declare_test!{StateTests_RandomTests_st201503181539GO, "StateTests/RandomTests/st201503181539GO"} -declare_test!{StateTests_RandomTests_st201503181540CPPJIT, "StateTests/RandomTests/st201503181540CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181540PYTHON, "StateTests/RandomTests/st201503181540PYTHON"} -declare_test!{StateTests_RandomTests_st201503181543GO, "StateTests/RandomTests/st201503181543GO"} -declare_test!{StateTests_RandomTests_st201503181544CPPJIT, "StateTests/RandomTests/st201503181544CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181544GO, "StateTests/RandomTests/st201503181544GO"} -declare_test!{StateTests_RandomTests_st201503181547GO, "StateTests/RandomTests/st201503181547GO"} -declare_test!{StateTests_RandomTests_st201503181548CPPJIT, "StateTests/RandomTests/st201503181548CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181548GO, "StateTests/RandomTests/st201503181548GO"} -declare_test!{StateTests_RandomTests_st201503181551GO, "StateTests/RandomTests/st201503181551GO"} -declare_test!{StateTests_RandomTests_st201503181552CPPJIT, "StateTests/RandomTests/st201503181552CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181553GO, "StateTests/RandomTests/st201503181553GO"} -declare_test!{StateTests_RandomTests_st201503181555CPPJIT, "StateTests/RandomTests/st201503181555CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181555GO, "StateTests/RandomTests/st201503181555GO"} -declare_test!{StateTests_RandomTests_st201503181557GO, "StateTests/RandomTests/st201503181557GO"} -declare_test!{StateTests_RandomTests_st201503181559GO, "StateTests/RandomTests/st201503181559GO"} -declare_test!{StateTests_RandomTests_st201503181601CPPJIT, "StateTests/RandomTests/st201503181601CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181601GO, "StateTests/RandomTests/st201503181601GO"} -declare_test!{StateTests_RandomTests_st201503181602GO, "StateTests/RandomTests/st201503181602GO"} -declare_test!{StateTests_RandomTests_st201503181603GO, "StateTests/RandomTests/st201503181603GO"} -declare_test!{StateTests_RandomTests_st201503181604GO, "StateTests/RandomTests/st201503181604GO"} -declare_test!{StateTests_RandomTests_st201503181605GO, "StateTests/RandomTests/st201503181605GO"} -declare_test!{StateTests_RandomTests_st201503181606GO, "StateTests/RandomTests/st201503181606GO"} -declare_test!{StateTests_RandomTests_st201503181607GO, "StateTests/RandomTests/st201503181607GO"} -declare_test!{StateTests_RandomTests_st201503181608CPPJIT, "StateTests/RandomTests/st201503181608CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181608GO, "StateTests/RandomTests/st201503181608GO"} -declare_test!{StateTests_RandomTests_st201503181609GO, "StateTests/RandomTests/st201503181609GO"} -declare_test!{StateTests_RandomTests_st201503181610CPPJIT, "StateTests/RandomTests/st201503181610CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181610GO, "StateTests/RandomTests/st201503181610GO"} -declare_test!{StateTests_RandomTests_st201503181611CPPJIT, "StateTests/RandomTests/st201503181611CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181611GO, "StateTests/RandomTests/st201503181611GO"} -declare_test!{StateTests_RandomTests_st201503181612GO, "StateTests/RandomTests/st201503181612GO"} -declare_test!{StateTests_RandomTests_st201503181614CPPJIT, "StateTests/RandomTests/st201503181614CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181614GO, "StateTests/RandomTests/st201503181614GO"} -declare_test!{StateTests_RandomTests_st201503181616CPPJIT, "StateTests/RandomTests/st201503181616CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181616GO, "StateTests/RandomTests/st201503181616GO"} -declare_test!{StateTests_RandomTests_st201503181617GO, "StateTests/RandomTests/st201503181617GO"} -declare_test!{StateTests_RandomTests_st201503181618GO, "StateTests/RandomTests/st201503181618GO"} -declare_test!{StateTests_RandomTests_st201503181619GO, "StateTests/RandomTests/st201503181619GO"} -declare_test!{StateTests_RandomTests_st201503181620CPPJIT, "StateTests/RandomTests/st201503181620CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181620GO, "StateTests/RandomTests/st201503181620GO"} -declare_test!{StateTests_RandomTests_st201503181621GO, "StateTests/RandomTests/st201503181621GO"} -declare_test!{StateTests_RandomTests_st201503181625GO, "StateTests/RandomTests/st201503181625GO"} -declare_test!{StateTests_RandomTests_st201503181626CPPJIT, "StateTests/RandomTests/st201503181626CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181626GO, "StateTests/RandomTests/st201503181626GO"} -declare_test!{StateTests_RandomTests_st201503181627GO, "StateTests/RandomTests/st201503181627GO"} -declare_test!{StateTests_RandomTests_st201503181628GO, "StateTests/RandomTests/st201503181628GO"} -declare_test!{StateTests_RandomTests_st201503181629GO, "StateTests/RandomTests/st201503181629GO"} -declare_test!{StateTests_RandomTests_st201503181630CPPJIT, "StateTests/RandomTests/st201503181630CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181630GO, "StateTests/RandomTests/st201503181630GO"} -declare_test!{StateTests_RandomTests_st201503181630PYTHON, "StateTests/RandomTests/st201503181630PYTHON"} -declare_test!{StateTests_RandomTests_st201503181632GO, "StateTests/RandomTests/st201503181632GO"} -declare_test!{StateTests_RandomTests_st201503181634CPPJIT, "StateTests/RandomTests/st201503181634CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181635GO, "StateTests/RandomTests/st201503181635GO"} -declare_test!{StateTests_RandomTests_st201503181636GO, "StateTests/RandomTests/st201503181636GO"} -declare_test!{StateTests_RandomTests_st201503181638GO, "StateTests/RandomTests/st201503181638GO"} -declare_test!{StateTests_RandomTests_st201503181639CPPJIT, "StateTests/RandomTests/st201503181639CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181641GO, "StateTests/RandomTests/st201503181641GO"} -declare_test!{StateTests_RandomTests_st201503181645GO, "StateTests/RandomTests/st201503181645GO"} -declare_test!{StateTests_RandomTests_st201503181646GO, "StateTests/RandomTests/st201503181646GO"} -declare_test!{StateTests_RandomTests_st201503181647CPPJIT, "StateTests/RandomTests/st201503181647CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181649CPPJIT, "StateTests/RandomTests/st201503181649CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181650GO, "StateTests/RandomTests/st201503181650GO"} -declare_test!{StateTests_RandomTests_st201503181652CPPJIT, "StateTests/RandomTests/st201503181652CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181653GO, "StateTests/RandomTests/st201503181653GO"} -declare_test!{StateTests_RandomTests_st201503181654GO, "StateTests/RandomTests/st201503181654GO"} -declare_test!{StateTests_RandomTests_st201503181655CPPJIT, "StateTests/RandomTests/st201503181655CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181655GO, "StateTests/RandomTests/st201503181655GO"} -declare_test!{StateTests_RandomTests_st201503181656CPPJIT, "StateTests/RandomTests/st201503181656CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181656GO, "StateTests/RandomTests/st201503181656GO"} -declare_test!{StateTests_RandomTests_st201503181657GO, "StateTests/RandomTests/st201503181657GO"} -declare_test!{StateTests_RandomTests_st201503181658GO, "StateTests/RandomTests/st201503181658GO"} -declare_test!{StateTests_RandomTests_st201503181700GO, "StateTests/RandomTests/st201503181700GO"} -declare_test!{StateTests_RandomTests_st201503181702GO, "StateTests/RandomTests/st201503181702GO"} -declare_test!{StateTests_RandomTests_st201503181703CPPJIT, "StateTests/RandomTests/st201503181703CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181703GO, "StateTests/RandomTests/st201503181703GO"} -declare_test!{StateTests_RandomTests_st201503181704GO, "StateTests/RandomTests/st201503181704GO"} -declare_test!{StateTests_RandomTests_st201503181706GO, "StateTests/RandomTests/st201503181706GO"} -declare_test!{StateTests_RandomTests_st201503181709GO, "StateTests/RandomTests/st201503181709GO"} -declare_test!{StateTests_RandomTests_st201503181711CPPJIT, "StateTests/RandomTests/st201503181711CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181711GO, "StateTests/RandomTests/st201503181711GO"} -declare_test!{StateTests_RandomTests_st201503181713CPPJIT, "StateTests/RandomTests/st201503181713CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181713GO, "StateTests/RandomTests/st201503181713GO"} -declare_test!{StateTests_RandomTests_st201503181714GO, "StateTests/RandomTests/st201503181714GO"} -declare_test!{StateTests_RandomTests_st201503181715CPPJIT, "StateTests/RandomTests/st201503181715CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181715GO, "StateTests/RandomTests/st201503181715GO"} -declare_test!{StateTests_RandomTests_st201503181716GO, "StateTests/RandomTests/st201503181716GO"} -declare_test!{StateTests_RandomTests_st201503181717GO, "StateTests/RandomTests/st201503181717GO"} -declare_test!{StateTests_RandomTests_st201503181720CPPJIT, "StateTests/RandomTests/st201503181720CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181722GO, "StateTests/RandomTests/st201503181722GO"} -declare_test!{StateTests_RandomTests_st201503181723CPPJIT, "StateTests/RandomTests/st201503181723CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181723GO, "StateTests/RandomTests/st201503181723GO"} -declare_test!{StateTests_RandomTests_st201503181724CPPJIT, "StateTests/RandomTests/st201503181724CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181724GO, "StateTests/RandomTests/st201503181724GO"} -declare_test!{StateTests_RandomTests_st201503181725GO, "StateTests/RandomTests/st201503181725GO"} -declare_test!{StateTests_RandomTests_st201503181728GO, "StateTests/RandomTests/st201503181728GO"} -declare_test!{StateTests_RandomTests_st201503181729GO, "StateTests/RandomTests/st201503181729GO"} -declare_test!{StateTests_RandomTests_st201503181730GO, "StateTests/RandomTests/st201503181730GO"} -declare_test!{StateTests_RandomTests_st201503181731CPPJIT, "StateTests/RandomTests/st201503181731CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181732GO, "StateTests/RandomTests/st201503181732GO"} -declare_test!{StateTests_RandomTests_st201503181734CPPJIT, "StateTests/RandomTests/st201503181734CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181734GO, "StateTests/RandomTests/st201503181734GO"} -declare_test!{StateTests_RandomTests_st201503181735GO, "StateTests/RandomTests/st201503181735GO"} -declare_test!{StateTests_RandomTests_st201503181737CPPJIT, "StateTests/RandomTests/st201503181737CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181737GO, "StateTests/RandomTests/st201503181737GO"} -declare_test!{StateTests_RandomTests_st201503181738CPPJIT, "StateTests/RandomTests/st201503181738CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181738GO, "StateTests/RandomTests/st201503181738GO"} -declare_test!{StateTests_RandomTests_st201503181739GO, "StateTests/RandomTests/st201503181739GO"} -declare_test!{StateTests_RandomTests_st201503181740CPPJIT, "StateTests/RandomTests/st201503181740CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181740GO, "StateTests/RandomTests/st201503181740GO"} -declare_test!{StateTests_RandomTests_st201503181742CPPJIT, "StateTests/RandomTests/st201503181742CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181743GO, "StateTests/RandomTests/st201503181743GO"} -declare_test!{StateTests_RandomTests_st201503181744GO, "StateTests/RandomTests/st201503181744GO"} -declare_test!{StateTests_RandomTests_st201503181745CPPJIT, "StateTests/RandomTests/st201503181745CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181746GO, "StateTests/RandomTests/st201503181746GO"} -declare_test!{StateTests_RandomTests_st201503181747GO, "StateTests/RandomTests/st201503181747GO"} -declare_test!{StateTests_RandomTests_st201503181748GO, "StateTests/RandomTests/st201503181748GO"} -declare_test!{StateTests_RandomTests_st201503181749GO, "StateTests/RandomTests/st201503181749GO"} -declare_test!{StateTests_RandomTests_st201503181750CPPJIT, "StateTests/RandomTests/st201503181750CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181750GO, "StateTests/RandomTests/st201503181750GO"} -declare_test!{StateTests_RandomTests_st201503181752GO, "StateTests/RandomTests/st201503181752GO"} -declare_test!{StateTests_RandomTests_st201503181753CPPJIT, "StateTests/RandomTests/st201503181753CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181754CPPJIT, "StateTests/RandomTests/st201503181754CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181754GO, "StateTests/RandomTests/st201503181754GO"} -declare_test!{StateTests_RandomTests_st201503181755CPPJIT, "StateTests/RandomTests/st201503181755CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181755GO, "StateTests/RandomTests/st201503181755GO"} -declare_test!{StateTests_RandomTests_st201503181756GO, "StateTests/RandomTests/st201503181756GO"} -declare_test!{StateTests_RandomTests_st201503181757CPPJIT, "StateTests/RandomTests/st201503181757CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181757GO, "StateTests/RandomTests/st201503181757GO"} -declare_test!{StateTests_RandomTests_st201503181759GO, "StateTests/RandomTests/st201503181759GO"} -declare_test!{StateTests_RandomTests_st201503181800GO, "StateTests/RandomTests/st201503181800GO"} -declare_test!{StateTests_RandomTests_st201503181801GO, "StateTests/RandomTests/st201503181801GO"} -declare_test!{StateTests_RandomTests_st201503181802GO, "StateTests/RandomTests/st201503181802GO"} -declare_test!{StateTests_RandomTests_st201503181803CPPJIT, "StateTests/RandomTests/st201503181803CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181803GO, "StateTests/RandomTests/st201503181803GO"} -declare_test!{StateTests_RandomTests_st201503181804GO, "StateTests/RandomTests/st201503181804GO"} -declare_test!{StateTests_RandomTests_st201503181806GO, "StateTests/RandomTests/st201503181806GO"} -declare_test!{StateTests_RandomTests_st201503181808GO, "StateTests/RandomTests/st201503181808GO"} -declare_test!{StateTests_RandomTests_st201503181809CPPJIT, "StateTests/RandomTests/st201503181809CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181812CPPJIT, "StateTests/RandomTests/st201503181812CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181812GO, "StateTests/RandomTests/st201503181812GO"} -declare_test!{StateTests_RandomTests_st201503181814CPPJIT, "StateTests/RandomTests/st201503181814CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181815GO, "StateTests/RandomTests/st201503181815GO"} -declare_test!{StateTests_RandomTests_st201503181816CPPJIT, "StateTests/RandomTests/st201503181816CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181817CPPJIT, "StateTests/RandomTests/st201503181817CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181819GO, "StateTests/RandomTests/st201503181819GO"} -declare_test!{StateTests_RandomTests_st201503181821GO, "StateTests/RandomTests/st201503181821GO"} -declare_test!{StateTests_RandomTests_st201503181822GO, "StateTests/RandomTests/st201503181822GO"} -declare_test!{StateTests_RandomTests_st201503181823GO, "StateTests/RandomTests/st201503181823GO"} -declare_test!{StateTests_RandomTests_st201503181824GO, "StateTests/RandomTests/st201503181824GO"} -declare_test!{StateTests_RandomTests_st201503181825GO, "StateTests/RandomTests/st201503181825GO"} -declare_test!{StateTests_RandomTests_st201503181829GO, "StateTests/RandomTests/st201503181829GO"} -declare_test!{StateTests_RandomTests_st201503181830CPPJIT, "StateTests/RandomTests/st201503181830CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181833GO, "StateTests/RandomTests/st201503181833GO"} -declare_test!{StateTests_RandomTests_st201503181834CPPJIT, "StateTests/RandomTests/st201503181834CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181834GO, "StateTests/RandomTests/st201503181834GO"} -declare_test!{StateTests_RandomTests_st201503181837GO, "StateTests/RandomTests/st201503181837GO"} -declare_test!{StateTests_RandomTests_st201503181840GO, "StateTests/RandomTests/st201503181840GO"} -declare_test!{StateTests_RandomTests_st201503181842GO, "StateTests/RandomTests/st201503181842GO"} -declare_test!{StateTests_RandomTests_st201503181843GO, "StateTests/RandomTests/st201503181843GO"} -declare_test!{StateTests_RandomTests_st201503181844GO, "StateTests/RandomTests/st201503181844GO"} -declare_test!{StateTests_RandomTests_st201503181845GO, "StateTests/RandomTests/st201503181845GO"} -declare_test!{StateTests_RandomTests_st201503181846GO, "StateTests/RandomTests/st201503181846GO"} -declare_test!{StateTests_RandomTests_st201503181847GO, "StateTests/RandomTests/st201503181847GO"} -declare_test!{StateTests_RandomTests_st201503181848GO, "StateTests/RandomTests/st201503181848GO"} -declare_test!{StateTests_RandomTests_st201503181849GO, "StateTests/RandomTests/st201503181849GO"} -declare_test!{StateTests_RandomTests_st201503181850GO, "StateTests/RandomTests/st201503181850GO"} -declare_test!{StateTests_RandomTests_st201503181851CPPJIT, "StateTests/RandomTests/st201503181851CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181851GO, "StateTests/RandomTests/st201503181851GO"} -declare_test!{StateTests_RandomTests_st201503181852CPPJIT, "StateTests/RandomTests/st201503181852CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181854GO, "StateTests/RandomTests/st201503181854GO"} -declare_test!{StateTests_RandomTests_st201503181855CPPJIT, "StateTests/RandomTests/st201503181855CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181857PYTHON, "StateTests/RandomTests/st201503181857PYTHON"} -declare_test!{StateTests_RandomTests_st201503181859GO, "StateTests/RandomTests/st201503181859GO"} -declare_test!{StateTests_RandomTests_st201503181900GO, "StateTests/RandomTests/st201503181900GO"} -declare_test!{StateTests_RandomTests_st201503181903GO, "StateTests/RandomTests/st201503181903GO"} -declare_test!{StateTests_RandomTests_st201503181904GO, "StateTests/RandomTests/st201503181904GO"} -declare_test!{StateTests_RandomTests_st201503181906GO, "StateTests/RandomTests/st201503181906GO"} -declare_test!{StateTests_RandomTests_st201503181907GO, "StateTests/RandomTests/st201503181907GO"} -declare_test!{StateTests_RandomTests_st201503181910GO, "StateTests/RandomTests/st201503181910GO"} -declare_test!{StateTests_RandomTests_st201503181915GO, "StateTests/RandomTests/st201503181915GO"} -declare_test!{StateTests_RandomTests_st201503181919CPPJIT, "StateTests/RandomTests/st201503181919CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181919PYTHON, "StateTests/RandomTests/st201503181919PYTHON"} -declare_test!{StateTests_RandomTests_st201503181920GO, "StateTests/RandomTests/st201503181920GO"} -declare_test!{StateTests_RandomTests_st201503181922GO, "StateTests/RandomTests/st201503181922GO"} -declare_test!{StateTests_RandomTests_st201503181926GO, "StateTests/RandomTests/st201503181926GO"} -declare_test!{StateTests_RandomTests_st201503181929GO, "StateTests/RandomTests/st201503181929GO"} -declare_test!{StateTests_RandomTests_st201503181931CPPJIT, "StateTests/RandomTests/st201503181931CPPJIT"} -declare_test!{StateTests_RandomTests_st201503181931GO, "StateTests/RandomTests/st201503181931GO"} -declare_test!{StateTests_RandomTests_st201503181931PYTHON, "StateTests/RandomTests/st201503181931PYTHON"} -declare_test!{StateTests_RandomTests_st201503191646GO, "StateTests/RandomTests/st201503191646GO"} -declare_test!{StateTests_RandomTests_st201503200837JS, "StateTests/RandomTests/st201503200837JS"} -declare_test!{StateTests_RandomTests_st201503200838JS, "StateTests/RandomTests/st201503200838JS"} -declare_test!{StateTests_RandomTests_st201503200841JS, "StateTests/RandomTests/st201503200841JS"} -declare_test!{StateTests_RandomTests_st201503200848JS, "StateTests/RandomTests/st201503200848JS"} -declare_test!{StateTests_RandomTests_st201503240609JS, "StateTests/RandomTests/st201503240609JS"} -declare_test!{StateTests_RandomTests_st201503302200JS, "StateTests/RandomTests/st201503302200JS"} -declare_test!{StateTests_RandomTests_st201503302202JS, "StateTests/RandomTests/st201503302202JS"} -declare_test!{StateTests_RandomTests_st201503302206JS, "StateTests/RandomTests/st201503302206JS"} -declare_test!{StateTests_RandomTests_st201503302208JS, "StateTests/RandomTests/st201503302208JS"} -declare_test!{StateTests_RandomTests_st201503302210JS, "StateTests/RandomTests/st201503302210JS"} -declare_test!{StateTests_RandomTests_st201503302211JS, "StateTests/RandomTests/st201503302211JS"} -declare_test!{StateTests_RandomTests_st201504011535GO, "StateTests/RandomTests/st201504011535GO"} -declare_test!{StateTests_RandomTests_st201504011536GO, "StateTests/RandomTests/st201504011536GO"} -declare_test!{StateTests_RandomTests_st201504011547GO, "StateTests/RandomTests/st201504011547GO"} -declare_test!{StateTests_RandomTests_st201504011916JS, "StateTests/RandomTests/st201504011916JS"} -declare_test!{StateTests_RandomTests_st201504012130JS, "StateTests/RandomTests/st201504012130JS"} -declare_test!{StateTests_RandomTests_st201504012259JS, "StateTests/RandomTests/st201504012259JS"} -declare_test!{StateTests_RandomTests_st201504012359JS, "StateTests/RandomTests/st201504012359JS"} -declare_test!{StateTests_RandomTests_st201504020305JS, "StateTests/RandomTests/st201504020305JS"} -declare_test!{StateTests_RandomTests_st201504020400JS, "StateTests/RandomTests/st201504020400JS"} -declare_test!{StateTests_RandomTests_st201504020428JS, "StateTests/RandomTests/st201504020428JS"} -declare_test!{StateTests_RandomTests_st201504020431JS, "StateTests/RandomTests/st201504020431JS"} -declare_test!{StateTests_RandomTests_st201504020444JS, "StateTests/RandomTests/st201504020444JS"} -declare_test!{StateTests_RandomTests_st201504020538JS, "StateTests/RandomTests/st201504020538JS"} -declare_test!{StateTests_RandomTests_st201504020639JS, "StateTests/RandomTests/st201504020639JS"} -declare_test!{StateTests_RandomTests_st201504020836JS, "StateTests/RandomTests/st201504020836JS"} -declare_test!{StateTests_RandomTests_st201504020910JS, "StateTests/RandomTests/st201504020910JS"} -declare_test!{StateTests_RandomTests_st201504021057JS, "StateTests/RandomTests/st201504021057JS"} -declare_test!{StateTests_RandomTests_st201504021104JS, "StateTests/RandomTests/st201504021104JS"} -declare_test!{StateTests_RandomTests_st201504021237CPPJIT, "StateTests/RandomTests/st201504021237CPPJIT"} -declare_test!{StateTests_RandomTests_st201504021237GO, "StateTests/RandomTests/st201504021237GO"} -declare_test!{StateTests_RandomTests_st201504021237JS, "StateTests/RandomTests/st201504021237JS"} -declare_test!{StateTests_RandomTests_st201504021237PYTHON, "StateTests/RandomTests/st201504021237PYTHON"} -declare_test!{StateTests_RandomTests_st201504021949JS, "StateTests/RandomTests/st201504021949JS"} -declare_test!{StateTests_RandomTests_st201504022003CPPJIT, "StateTests/RandomTests/st201504022003CPPJIT"} -declare_test!{StateTests_RandomTests_st201504022124JS, "StateTests/RandomTests/st201504022124JS"} -declare_test!{StateTests_RandomTests_st201504030138JS, "StateTests/RandomTests/st201504030138JS"} -declare_test!{StateTests_RandomTests_st201504030646JS, "StateTests/RandomTests/st201504030646JS"} -declare_test!{StateTests_RandomTests_st201504030709JS, "StateTests/RandomTests/st201504030709JS"} -declare_test!{StateTests_RandomTests_st201504031133JS, "StateTests/RandomTests/st201504031133JS"} -declare_test!{StateTests_RandomTests_st201504031446JS, "StateTests/RandomTests/st201504031446JS"} -declare_test!{StateTests_RandomTests_st201504031841JS, "StateTests/RandomTests/st201504031841JS"} -declare_test!{StateTests_RandomTests_st201504041605JS, "StateTests/RandomTests/st201504041605JS"} -declare_test!{StateTests_RandomTests_st201504042052JS, "StateTests/RandomTests/st201504042052JS"} -declare_test!{StateTests_RandomTests_st201504042226CPPJIT, "StateTests/RandomTests/st201504042226CPPJIT"} -declare_test!{StateTests_RandomTests_st201504042355CPPJIT, "StateTests/RandomTests/st201504042355CPPJIT"} -declare_test!{StateTests_RandomTests_st201504050059JS, "StateTests/RandomTests/st201504050059JS"} -declare_test!{StateTests_RandomTests_st201504050733JS, "StateTests/RandomTests/st201504050733JS"} -declare_test!{StateTests_RandomTests_st201504051540JS, "StateTests/RandomTests/st201504051540JS"} -declare_test!{StateTests_RandomTests_st201504051944CPPJIT, "StateTests/RandomTests/st201504051944CPPJIT"} -declare_test!{StateTests_RandomTests_st201504052008CPPJIT, "StateTests/RandomTests/st201504052008CPPJIT"} -declare_test!{StateTests_RandomTests_st201504052014GO, "StateTests/RandomTests/st201504052014GO"} -declare_test!{StateTests_RandomTests_st201504052031CPPJIT, "StateTests/RandomTests/st201504052031CPPJIT"} -declare_test!{StateTests_RandomTests_st201504060057CPPJIT, "StateTests/RandomTests/st201504060057CPPJIT"} -declare_test!{StateTests_RandomTests_st201504060418CPPJIT, "StateTests/RandomTests/st201504060418CPPJIT"} -declare_test!{StateTests_RandomTests_st201504061106CPPJIT, "StateTests/RandomTests/st201504061106CPPJIT"} -declare_test!{StateTests_RandomTests_st201504061134CPPJIT, "StateTests/RandomTests/st201504061134CPPJIT"} -declare_test!{StateTests_RandomTests_st201504062033CPPJIT, "StateTests/RandomTests/st201504062033CPPJIT"} -declare_test!{StateTests_RandomTests_st201504062046CPPJIT, "StateTests/RandomTests/st201504062046CPPJIT"} -declare_test!{StateTests_RandomTests_st201504062314CPPJIT, "StateTests/RandomTests/st201504062314CPPJIT"} -declare_test!{StateTests_RandomTests_st201504070746JS, "StateTests/RandomTests/st201504070746JS"} -declare_test!{StateTests_RandomTests_st201504070816CPPJIT, "StateTests/RandomTests/st201504070816CPPJIT"} -declare_test!{StateTests_RandomTests_st201504070836CPPJIT, "StateTests/RandomTests/st201504070836CPPJIT"} -declare_test!{StateTests_RandomTests_st201504070839CPPJIT, "StateTests/RandomTests/st201504070839CPPJIT"} -declare_test!{StateTests_RandomTests_st201504071041CPPJIT, "StateTests/RandomTests/st201504071041CPPJIT"} -declare_test!{StateTests_RandomTests_st201504071056CPPJIT, "StateTests/RandomTests/st201504071056CPPJIT"} -declare_test!{StateTests_RandomTests_st201504071621CPPJIT, "StateTests/RandomTests/st201504071621CPPJIT"} -declare_test!{StateTests_RandomTests_st201504071653CPPJIT, "StateTests/RandomTests/st201504071653CPPJIT"} -declare_test!{StateTests_RandomTests_st201504071750CPPJIT, "StateTests/RandomTests/st201504071750CPPJIT"} -declare_test!{StateTests_RandomTests_st201504071905CPPJIT, "StateTests/RandomTests/st201504071905CPPJIT"} -declare_test!{StateTests_RandomTests_st201504080454CPPJIT, "StateTests/RandomTests/st201504080454CPPJIT"} -declare_test!{StateTests_RandomTests_st201504080457CPPJIT, "StateTests/RandomTests/st201504080457CPPJIT"} -declare_test!{StateTests_RandomTests_st201504080650CPPJIT, "StateTests/RandomTests/st201504080650CPPJIT"} -declare_test!{StateTests_RandomTests_st201504080840CPPJIT, "StateTests/RandomTests/st201504080840CPPJIT"} -declare_test!{StateTests_RandomTests_st201504080948CPPJIT, "StateTests/RandomTests/st201504080948CPPJIT"} -declare_test!{StateTests_RandomTests_st201504081100CPPJIT, "StateTests/RandomTests/st201504081100CPPJIT"} -declare_test!{StateTests_RandomTests_st201504081134CPPJIT, "StateTests/RandomTests/st201504081134CPPJIT"} -declare_test!{StateTests_RandomTests_st201504081138CPPJIT, "StateTests/RandomTests/st201504081138CPPJIT"} -declare_test!{StateTests_RandomTests_st201504081611CPPJIT, "StateTests/RandomTests/st201504081611CPPJIT"} -declare_test!{StateTests_RandomTests_st201504081841JAVA, "StateTests/RandomTests/st201504081841JAVA"} -declare_test!{StateTests_RandomTests_st201504081842JAVA, "StateTests/RandomTests/st201504081842JAVA"} -declare_test!{StateTests_RandomTests_st201504081843JAVA, "StateTests/RandomTests/st201504081843JAVA"} -declare_test!{StateTests_RandomTests_st201504081928CPPJIT, "StateTests/RandomTests/st201504081928CPPJIT"} -declare_test!{StateTests_RandomTests_st201504081953JAVA, "StateTests/RandomTests/st201504081953JAVA"} -declare_test!{StateTests_RandomTests_st201504081954JAVA, "StateTests/RandomTests/st201504081954JAVA"} -declare_test!{StateTests_RandomTests_st201504081955JAVA, "StateTests/RandomTests/st201504081955JAVA"} -declare_test!{StateTests_RandomTests_st201504081956JAVA, "StateTests/RandomTests/st201504081956JAVA"} -declare_test!{StateTests_RandomTests_st201504081957JAVA, "StateTests/RandomTests/st201504081957JAVA"} -declare_test!{StateTests_RandomTests_st201504082000JAVA, "StateTests/RandomTests/st201504082000JAVA"} -declare_test!{StateTests_RandomTests_st201504082001JAVA, "StateTests/RandomTests/st201504082001JAVA"} -declare_test!{StateTests_RandomTests_st201504082002JAVA, "StateTests/RandomTests/st201504082002JAVA"} -declare_test!{StateTests_RandomTests_st201504090553CPPJIT, "StateTests/RandomTests/st201504090553CPPJIT"} -declare_test!{StateTests_RandomTests_st201504090657CPPJIT, "StateTests/RandomTests/st201504090657CPPJIT"} -declare_test!{StateTests_RandomTests_st201504091403CPPJIT, "StateTests/RandomTests/st201504091403CPPJIT"} -declare_test!{StateTests_RandomTests_st201504091641CPPJIT, "StateTests/RandomTests/st201504091641CPPJIT"} -declare_test!{StateTests_RandomTests_st201504092303CPPJIT, "StateTests/RandomTests/st201504092303CPPJIT"} -declare_test!{StateTests_RandomTests_st201504100125CPPJIT, "StateTests/RandomTests/st201504100125CPPJIT"} -declare_test!{StateTests_RandomTests_st201504100215CPPJIT, "StateTests/RandomTests/st201504100215CPPJIT"} -declare_test!{StateTests_RandomTests_st201504100226PYTHON, "StateTests/RandomTests/st201504100226PYTHON"} -declare_test!{StateTests_RandomTests_st201504100308CPPJIT, "StateTests/RandomTests/st201504100308CPPJIT"} -declare_test!{StateTests_RandomTests_st201504100337CPPJIT, "StateTests/RandomTests/st201504100337CPPJIT"} -declare_test!{StateTests_RandomTests_st201504100341CPPJIT, "StateTests/RandomTests/st201504100341CPPJIT"} -declare_test!{StateTests_RandomTests_st201504101009CPPJIT, "StateTests/RandomTests/st201504101009CPPJIT"} -declare_test!{StateTests_RandomTests_st201504101150CPPJIT, "StateTests/RandomTests/st201504101150CPPJIT"} -declare_test!{StateTests_RandomTests_st201504101223CPPJIT, "StateTests/RandomTests/st201504101223CPPJIT"} -declare_test!{StateTests_RandomTests_st201504101338CPPJIT, "StateTests/RandomTests/st201504101338CPPJIT"} -declare_test!{StateTests_RandomTests_st201504101754PYTHON, "StateTests/RandomTests/st201504101754PYTHON"} -declare_test!{StateTests_RandomTests_st201504111554CPPJIT, "StateTests/RandomTests/st201504111554CPPJIT"} -declare_test!{StateTests_RandomTests_st201504130653JS, "StateTests/RandomTests/st201504130653JS"} -declare_test!{StateTests_RandomTests_st201504131821CPPJIT, "StateTests/RandomTests/st201504131821CPPJIT"} -declare_test!{StateTests_RandomTests_st201504140229CPPJIT, "StateTests/RandomTests/st201504140229CPPJIT"} -declare_test!{StateTests_RandomTests_st201504140236CPPJIT, "StateTests/RandomTests/st201504140236CPPJIT"} -declare_test!{StateTests_RandomTests_st201504140359CPPJIT, "StateTests/RandomTests/st201504140359CPPJIT"} -declare_test!{StateTests_RandomTests_st201504140750CPPJIT, "StateTests/RandomTests/st201504140750CPPJIT"} -declare_test!{StateTests_RandomTests_st201504140818CPPJIT, "StateTests/RandomTests/st201504140818CPPJIT"} -declare_test!{StateTests_RandomTests_st201504140900CPPJIT, "StateTests/RandomTests/st201504140900CPPJIT"} -declare_test!{StateTests_RandomTests_st201504150854CPPJIT, "StateTests/RandomTests/st201504150854CPPJIT"} -declare_test!{StateTests_RandomTests_st201504151057CPPJIT, "StateTests/RandomTests/st201504151057CPPJIT"} -declare_test!{StateTests_RandomTests_st201504202124CPPJIT, "StateTests/RandomTests/st201504202124CPPJIT"} -declare_test!{StateTests_RandomTests_st201504210245CPPJIT, "StateTests/RandomTests/st201504210245CPPJIT"} -declare_test!{StateTests_RandomTests_st201504210957CPPJIT, "StateTests/RandomTests/st201504210957CPPJIT"} -declare_test!{StateTests_RandomTests_st201504211739CPPJIT, "StateTests/RandomTests/st201504211739CPPJIT"} -declare_test!{StateTests_RandomTests_st201504212038CPPJIT, "StateTests/RandomTests/st201504212038CPPJIT"} -declare_test!{StateTests_RandomTests_st201504230729CPPJIT, "StateTests/RandomTests/st201504230729CPPJIT"} -declare_test!{StateTests_RandomTests_st201504231639CPPJIT, "StateTests/RandomTests/st201504231639CPPJIT"} -declare_test!{StateTests_RandomTests_st201504231710CPPJIT, "StateTests/RandomTests/st201504231710CPPJIT"} -declare_test!{StateTests_RandomTests_st201504231742CPPJIT, "StateTests/RandomTests/st201504231742CPPJIT"} -declare_test!{StateTests_RandomTests_st201504232350CPPJIT, "StateTests/RandomTests/st201504232350CPPJIT"} -declare_test!{StateTests_RandomTests_st201504240140CPPJIT, "StateTests/RandomTests/st201504240140CPPJIT"} -declare_test!{StateTests_RandomTests_st201504240220CPPJIT, "StateTests/RandomTests/st201504240220CPPJIT"} -declare_test!{StateTests_RandomTests_st201504240351CPPJIT, "StateTests/RandomTests/st201504240351CPPJIT"} -declare_test!{StateTests_RandomTests_st201504240817CPPJIT, "StateTests/RandomTests/st201504240817CPPJIT"} -declare_test!{StateTests_RandomTests_st201504241118CPPJIT, "StateTests/RandomTests/st201504241118CPPJIT"} -declare_test!{StateTests_RandomTests_st201505021810CPPJIT, "StateTests/RandomTests/st201505021810CPPJIT"} -declare_test!{StateTests_RandomTests_st201505050557JS, "StateTests/RandomTests/st201505050557JS"} -declare_test!{StateTests_RandomTests_st201505050929GO, "StateTests/RandomTests/st201505050929GO"} -declare_test!{StateTests_RandomTests_st201505050942PYTHON, "StateTests/RandomTests/st201505050942PYTHON"} -declare_test!{StateTests_RandomTests_st201505051004PYTHON, "StateTests/RandomTests/st201505051004PYTHON"} -declare_test!{StateTests_RandomTests_st201505051016PYTHON, "StateTests/RandomTests/st201505051016PYTHON"} -declare_test!{StateTests_RandomTests_st201505051114GO, "StateTests/RandomTests/st201505051114GO"} -declare_test!{StateTests_RandomTests_st201505051238GO, "StateTests/RandomTests/st201505051238GO"} -declare_test!{StateTests_RandomTests_st201505051249GO, "StateTests/RandomTests/st201505051249GO"} -declare_test!{StateTests_RandomTests_st201505051558PYTHON, "StateTests/RandomTests/st201505051558PYTHON"} -declare_test!{StateTests_RandomTests_st201505051611PYTHON, "StateTests/RandomTests/st201505051611PYTHON"} -declare_test!{StateTests_RandomTests_st201505051648JS, "StateTests/RandomTests/st201505051648JS"} -declare_test!{StateTests_RandomTests_st201505051710GO, "StateTests/RandomTests/st201505051710GO"} -declare_test!{StateTests_RandomTests_st201505052013GO, "StateTests/RandomTests/st201505052013GO"} -declare_test!{StateTests_RandomTests_st201505052102JS, "StateTests/RandomTests/st201505052102JS"} -declare_test!{StateTests_RandomTests_st201505052235GO, "StateTests/RandomTests/st201505052235GO"} -declare_test!{StateTests_RandomTests_st201505052238JS, "StateTests/RandomTests/st201505052238JS"} -declare_test!{StateTests_RandomTests_st201505052242PYTHON, "StateTests/RandomTests/st201505052242PYTHON"} -declare_test!{StateTests_RandomTests_st201505052343PYTHON, "StateTests/RandomTests/st201505052343PYTHON"} -declare_test!{StateTests_RandomTests_st201505060120GO, "StateTests/RandomTests/st201505060120GO"} -declare_test!{StateTests_RandomTests_st201505060121GO, "StateTests/RandomTests/st201505060121GO"} -declare_test!{StateTests_RandomTests_st201505060136PYTHON, "StateTests/RandomTests/st201505060136PYTHON"} -declare_test!{StateTests_RandomTests_st201505060646JS, "StateTests/RandomTests/st201505060646JS"} -declare_test!{StateTests_RandomTests_st201505252314CPPJIT, "StateTests/RandomTests/st201505252314CPPJIT"} -declare_test!{StateTests_RandomTests_st201505272131CPPJIT, "StateTests/RandomTests/st201505272131CPPJIT"} -declare_test!{StateTests_RandomTests_st201506040034GO, "StateTests/RandomTests/st201506040034GO"} -declare_test!{StateTests_RandomTests_st201506040157GO, "StateTests/RandomTests/st201506040157GO"} -declare_test!{StateTests_RandomTests_st201506052130GO, "StateTests/RandomTests/st201506052130GO"} -declare_test!{StateTests_RandomTests_st201506060929GO, "StateTests/RandomTests/st201506060929GO"} -declare_test!{StateTests_RandomTests_st201506061255GO, "StateTests/RandomTests/st201506061255GO"} -declare_test!{StateTests_RandomTests_st201506062331GO, "StateTests/RandomTests/st201506062331GO"} -declare_test!{StateTests_RandomTests_st201506070548GO, "StateTests/RandomTests/st201506070548GO"} -declare_test!{StateTests_RandomTests_st201506071050GO, "StateTests/RandomTests/st201506071050GO"} -declare_test!{StateTests_RandomTests_st201506071624GO, "StateTests/RandomTests/st201506071624GO"} -declare_test!{StateTests_RandomTests_st201506071819GO, "StateTests/RandomTests/st201506071819GO"} -declare_test!{StateTests_RandomTests_st201506072007GO, "StateTests/RandomTests/st201506072007GO"} -declare_test!{StateTests_RandomTests_st201506080556GO, "StateTests/RandomTests/st201506080556GO"} -declare_test!{StateTests_RandomTests_st201506080721GO, "StateTests/RandomTests/st201506080721GO"} -declare_test!{StateTests_RandomTests_st201506091836GO, "StateTests/RandomTests/st201506091836GO"} -declare_test!{StateTests_RandomTests_st201506092032GO, "StateTests/RandomTests/st201506092032GO"} -declare_test!{StateTests_RandomTests_st201506101359JS, "StateTests/RandomTests/st201506101359JS"} -declare_test!{StateTests_RandomTests_st201507030359GO, "StateTests/RandomTests/st201507030359GO"} + declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} + declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} + declare_test!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} + declare_test!{StateTests_stExample, "StateTests/stExample"} + declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"} + declare_test!{StateTests_stLogTests, "StateTests/stLogTests"} + declare_test!{heavy => StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"} + declare_test!{heavy => StateTests_stMemoryTest, "StateTests/stMemoryTest"} + declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"} + declare_test!{heavy => StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} + declare_test!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} + declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} + declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} + declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} + declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} + declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} + declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} + declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} + + declare_test!{StateTests_RandomTests_st201503121803PYTHON, "StateTests/RandomTests/st201503121803PYTHON"} + declare_test!{StateTests_RandomTests_st201503121806PYTHON, "StateTests/RandomTests/st201503121806PYTHON"} + declare_test!{StateTests_RandomTests_st201503121848GO, "StateTests/RandomTests/st201503121848GO"} + declare_test!{StateTests_RandomTests_st201503121849GO, "StateTests/RandomTests/st201503121849GO"} + declare_test!{StateTests_RandomTests_st201503121850GO, "StateTests/RandomTests/st201503121850GO"} + declare_test!{StateTests_RandomTests_st201503121851GO, "StateTests/RandomTests/st201503121851GO"} + declare_test!{StateTests_RandomTests_st201503121953GO, "StateTests/RandomTests/st201503121953GO"} + declare_test!{StateTests_RandomTests_st201503122023GO, "StateTests/RandomTests/st201503122023GO"} + declare_test!{StateTests_RandomTests_st201503122023PYTHON, "StateTests/RandomTests/st201503122023PYTHON"} + declare_test!{StateTests_RandomTests_st201503122027GO, "StateTests/RandomTests/st201503122027GO"} + declare_test!{StateTests_RandomTests_st201503122054GO, "StateTests/RandomTests/st201503122054GO"} + declare_test!{StateTests_RandomTests_st201503122055GO, "StateTests/RandomTests/st201503122055GO"} + declare_test!{StateTests_RandomTests_st201503122115CPPJIT, "StateTests/RandomTests/st201503122115CPPJIT"} + declare_test!{StateTests_RandomTests_st201503122115GO, "StateTests/RandomTests/st201503122115GO"} + declare_test!{StateTests_RandomTests_st201503122123GO, "StateTests/RandomTests/st201503122123GO"} + declare_test!{StateTests_RandomTests_st201503122124GO, "StateTests/RandomTests/st201503122124GO"} + declare_test!{StateTests_RandomTests_st201503122128PYTHON, "StateTests/RandomTests/st201503122128PYTHON"} + declare_test!{StateTests_RandomTests_st201503122140GO, "StateTests/RandomTests/st201503122140GO"} + declare_test!{StateTests_RandomTests_st201503122159GO, "StateTests/RandomTests/st201503122159GO"} + declare_test!{StateTests_RandomTests_st201503122204GO, "StateTests/RandomTests/st201503122204GO"} + declare_test!{StateTests_RandomTests_st201503122212GO, "StateTests/RandomTests/st201503122212GO"} + declare_test!{StateTests_RandomTests_st201503122231GO, "StateTests/RandomTests/st201503122231GO"} + declare_test!{StateTests_RandomTests_st201503122238GO, "StateTests/RandomTests/st201503122238GO"} + declare_test!{StateTests_RandomTests_st201503122252GO, "StateTests/RandomTests/st201503122252GO"} + declare_test!{StateTests_RandomTests_st201503122316GO, "StateTests/RandomTests/st201503122316GO"} + declare_test!{StateTests_RandomTests_st201503122324GO, "StateTests/RandomTests/st201503122324GO"} + declare_test!{StateTests_RandomTests_st201503122358GO, "StateTests/RandomTests/st201503122358GO"} + declare_test!{StateTests_RandomTests_st201503130002GO, "StateTests/RandomTests/st201503130002GO"} + declare_test!{StateTests_RandomTests_st201503130005GO, "StateTests/RandomTests/st201503130005GO"} + declare_test!{StateTests_RandomTests_st201503130007GO, "StateTests/RandomTests/st201503130007GO"} + declare_test!{StateTests_RandomTests_st201503130010GO, "StateTests/RandomTests/st201503130010GO"} + declare_test!{StateTests_RandomTests_st201503130023PYTHON, "StateTests/RandomTests/st201503130023PYTHON"} + declare_test!{StateTests_RandomTests_st201503130059GO, "StateTests/RandomTests/st201503130059GO"} + declare_test!{StateTests_RandomTests_st201503130101GO, "StateTests/RandomTests/st201503130101GO"} + declare_test!{StateTests_RandomTests_st201503130109GO, "StateTests/RandomTests/st201503130109GO"} + declare_test!{StateTests_RandomTests_st201503130117GO, "StateTests/RandomTests/st201503130117GO"} + declare_test!{StateTests_RandomTests_st201503130122GO, "StateTests/RandomTests/st201503130122GO"} + declare_test!{StateTests_RandomTests_st201503130156GO, "StateTests/RandomTests/st201503130156GO"} + declare_test!{StateTests_RandomTests_st201503130156PYTHON, "StateTests/RandomTests/st201503130156PYTHON"} + declare_test!{StateTests_RandomTests_st201503130207GO, "StateTests/RandomTests/st201503130207GO"} + declare_test!{StateTests_RandomTests_st201503130219CPPJIT, "StateTests/RandomTests/st201503130219CPPJIT"} + declare_test!{StateTests_RandomTests_st201503130219GO, "StateTests/RandomTests/st201503130219GO"} + declare_test!{StateTests_RandomTests_st201503130243GO, "StateTests/RandomTests/st201503130243GO"} + declare_test!{StateTests_RandomTests_st201503130246GO, "StateTests/RandomTests/st201503130246GO"} + declare_test!{StateTests_RandomTests_st201503130321GO, "StateTests/RandomTests/st201503130321GO"} + declare_test!{StateTests_RandomTests_st201503130322GO, "StateTests/RandomTests/st201503130322GO"} + declare_test!{StateTests_RandomTests_st201503130332GO, "StateTests/RandomTests/st201503130332GO"} + declare_test!{StateTests_RandomTests_st201503130359GO, "StateTests/RandomTests/st201503130359GO"} + declare_test!{StateTests_RandomTests_st201503130405GO, "StateTests/RandomTests/st201503130405GO"} + declare_test!{StateTests_RandomTests_st201503130408GO, "StateTests/RandomTests/st201503130408GO"} + declare_test!{StateTests_RandomTests_st201503130411GO, "StateTests/RandomTests/st201503130411GO"} + declare_test!{StateTests_RandomTests_st201503130431GO, "StateTests/RandomTests/st201503130431GO"} + declare_test!{StateTests_RandomTests_st201503130437GO, "StateTests/RandomTests/st201503130437GO"} + declare_test!{StateTests_RandomTests_st201503130450GO, "StateTests/RandomTests/st201503130450GO"} + declare_test!{StateTests_RandomTests_st201503130512CPPJIT, "StateTests/RandomTests/st201503130512CPPJIT"} + declare_test!{StateTests_RandomTests_st201503130512GO, "StateTests/RandomTests/st201503130512GO"} + declare_test!{StateTests_RandomTests_st201503130615GO, "StateTests/RandomTests/st201503130615GO"} + declare_test!{StateTests_RandomTests_st201503130705GO, "StateTests/RandomTests/st201503130705GO"} + declare_test!{StateTests_RandomTests_st201503130733CPPJIT, "StateTests/RandomTests/st201503130733CPPJIT"} + declare_test!{StateTests_RandomTests_st201503130733GO, "StateTests/RandomTests/st201503130733GO"} + declare_test!{StateTests_RandomTests_st201503130747GO, "StateTests/RandomTests/st201503130747GO"} + declare_test!{StateTests_RandomTests_st201503130751GO, "StateTests/RandomTests/st201503130751GO"} + declare_test!{StateTests_RandomTests_st201503130752PYTHON, "StateTests/RandomTests/st201503130752PYTHON"} + declare_test!{StateTests_RandomTests_st201503130757PYTHON, "StateTests/RandomTests/st201503130757PYTHON"} + declare_test!{StateTests_RandomTests_st201503131658GO, "StateTests/RandomTests/st201503131658GO"} + declare_test!{StateTests_RandomTests_st201503131739GO, "StateTests/RandomTests/st201503131739GO"} + declare_test!{StateTests_RandomTests_st201503131755CPPJIT, "StateTests/RandomTests/st201503131755CPPJIT"} + declare_test!{StateTests_RandomTests_st201503131755GO, "StateTests/RandomTests/st201503131755GO"} + declare_test!{StateTests_RandomTests_st201503132001CPPJIT, "StateTests/RandomTests/st201503132001CPPJIT"} + declare_test!{StateTests_RandomTests_st201503132127PYTHON, "StateTests/RandomTests/st201503132127PYTHON"} + declare_test!{StateTests_RandomTests_st201503132201CPPJIT, "StateTests/RandomTests/st201503132201CPPJIT"} + declare_test!{StateTests_RandomTests_st201503132201GO, "StateTests/RandomTests/st201503132201GO"} + declare_test!{StateTests_RandomTests_st201503132202PYTHON, "StateTests/RandomTests/st201503132202PYTHON"} + declare_test!{StateTests_RandomTests_st201503140002PYTHON, "StateTests/RandomTests/st201503140002PYTHON"} + declare_test!{StateTests_RandomTests_st201503140240PYTHON, "StateTests/RandomTests/st201503140240PYTHON"} + declare_test!{StateTests_RandomTests_st201503140522PYTHON, "StateTests/RandomTests/st201503140522PYTHON"} + declare_test!{StateTests_RandomTests_st201503140756PYTHON, "StateTests/RandomTests/st201503140756PYTHON"} + declare_test!{StateTests_RandomTests_st201503141144PYTHON, "StateTests/RandomTests/st201503141144PYTHON"} + declare_test!{StateTests_RandomTests_st201503141510PYTHON, "StateTests/RandomTests/st201503141510PYTHON"} + declare_test!{StateTests_RandomTests_st201503150427PYTHON, "StateTests/RandomTests/st201503150427PYTHON"} + declare_test!{StateTests_RandomTests_st201503150716PYTHON, "StateTests/RandomTests/st201503150716PYTHON"} + declare_test!{StateTests_RandomTests_st201503151450PYTHON, "StateTests/RandomTests/st201503151450PYTHON"} + declare_test!{StateTests_RandomTests_st201503151516PYTHON, "StateTests/RandomTests/st201503151516PYTHON"} + declare_test!{StateTests_RandomTests_st201503151753PYTHON, "StateTests/RandomTests/st201503151753PYTHON"} + declare_test!{StateTests_RandomTests_st201503152057PYTHON, "StateTests/RandomTests/st201503152057PYTHON"} + declare_test!{StateTests_RandomTests_st201503152241PYTHON, "StateTests/RandomTests/st201503152241PYTHON"} + declare_test!{StateTests_RandomTests_st201503160014PYTHON, "StateTests/RandomTests/st201503160014PYTHON"} + declare_test!{StateTests_RandomTests_st201503160733PYTHON, "StateTests/RandomTests/st201503160733PYTHON"} + declare_test!{StateTests_RandomTests_st201503170051PYTHON, "StateTests/RandomTests/st201503170051PYTHON"} + declare_test!{StateTests_RandomTests_st201503170433PYTHON, "StateTests/RandomTests/st201503170433PYTHON"} + declare_test!{StateTests_RandomTests_st201503170523PYTHON, "StateTests/RandomTests/st201503170523PYTHON"} + declare_test!{StateTests_RandomTests_st201503171108PYTHON, "StateTests/RandomTests/st201503171108PYTHON"} + declare_test!{StateTests_RandomTests_st201503181223GO, "StateTests/RandomTests/st201503181223GO"} + declare_test!{StateTests_RandomTests_st201503181225GO, "StateTests/RandomTests/st201503181225GO"} + declare_test!{StateTests_RandomTests_st201503181226CPPJIT, "StateTests/RandomTests/st201503181226CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181227CPPJIT, "StateTests/RandomTests/st201503181227CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181227GO, "StateTests/RandomTests/st201503181227GO"} + declare_test!{StateTests_RandomTests_st201503181229GO, "StateTests/RandomTests/st201503181229GO"} + declare_test!{StateTests_RandomTests_st201503181230CPPJIT, "StateTests/RandomTests/st201503181230CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181230GO, "StateTests/RandomTests/st201503181230GO"} + declare_test!{StateTests_RandomTests_st201503181231GO, "StateTests/RandomTests/st201503181231GO"} + declare_test!{StateTests_RandomTests_st201503181232CPPJIT, "StateTests/RandomTests/st201503181232CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181232GO, "StateTests/RandomTests/st201503181232GO"} + declare_test!{StateTests_RandomTests_st201503181233GO, "StateTests/RandomTests/st201503181233GO"} + declare_test!{StateTests_RandomTests_st201503181234CPPJIT, "StateTests/RandomTests/st201503181234CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181234GO, "StateTests/RandomTests/st201503181234GO"} + declare_test!{StateTests_RandomTests_st201503181235CPPJIT, "StateTests/RandomTests/st201503181235CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181235GO, "StateTests/RandomTests/st201503181235GO"} + declare_test!{StateTests_RandomTests_st201503181236GO, "StateTests/RandomTests/st201503181236GO"} + declare_test!{StateTests_RandomTests_st201503181237GO, "StateTests/RandomTests/st201503181237GO"} + declare_test!{StateTests_RandomTests_st201503181239GO, "StateTests/RandomTests/st201503181239GO"} + declare_test!{StateTests_RandomTests_st201503181241CPPJIT, "StateTests/RandomTests/st201503181241CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181241GO, "StateTests/RandomTests/st201503181241GO"} + declare_test!{StateTests_RandomTests_st201503181243GO, "StateTests/RandomTests/st201503181243GO"} + declare_test!{StateTests_RandomTests_st201503181244GO, "StateTests/RandomTests/st201503181244GO"} + declare_test!{StateTests_RandomTests_st201503181245CPPJIT, "StateTests/RandomTests/st201503181245CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181245GO, "StateTests/RandomTests/st201503181245GO"} + declare_test!{StateTests_RandomTests_st201503181246CPPJIT, "StateTests/RandomTests/st201503181246CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181246GO, "StateTests/RandomTests/st201503181246GO"} + declare_test!{StateTests_RandomTests_st201503181247GO, "StateTests/RandomTests/st201503181247GO"} + declare_test!{StateTests_RandomTests_st201503181248GO, "StateTests/RandomTests/st201503181248GO"} + declare_test!{StateTests_RandomTests_st201503181249GO, "StateTests/RandomTests/st201503181249GO"} + declare_test!{StateTests_RandomTests_st201503181250CPPJIT, "StateTests/RandomTests/st201503181250CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181250GO, "StateTests/RandomTests/st201503181250GO"} + declare_test!{StateTests_RandomTests_st201503181251GO, "StateTests/RandomTests/st201503181251GO"} + declare_test!{StateTests_RandomTests_st201503181252CPPJIT, "StateTests/RandomTests/st201503181252CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181253GO, "StateTests/RandomTests/st201503181253GO"} + declare_test!{StateTests_RandomTests_st201503181255CPPJIT, "StateTests/RandomTests/st201503181255CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181255GO, "StateTests/RandomTests/st201503181255GO"} + declare_test!{StateTests_RandomTests_st201503181257GO, "StateTests/RandomTests/st201503181257GO"} + declare_test!{StateTests_RandomTests_st201503181258CPPJIT, "StateTests/RandomTests/st201503181258CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181258GO, "StateTests/RandomTests/st201503181258GO"} + declare_test!{StateTests_RandomTests_st201503181301CPPJIT, "StateTests/RandomTests/st201503181301CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181301GO, "StateTests/RandomTests/st201503181301GO"} + declare_test!{StateTests_RandomTests_st201503181303GO, "StateTests/RandomTests/st201503181303GO"} + declare_test!{StateTests_RandomTests_st201503181304GO, "StateTests/RandomTests/st201503181304GO"} + declare_test!{StateTests_RandomTests_st201503181305GO, "StateTests/RandomTests/st201503181305GO"} + declare_test!{StateTests_RandomTests_st201503181306GO, "StateTests/RandomTests/st201503181306GO"} + declare_test!{StateTests_RandomTests_st201503181307CPPJIT, "StateTests/RandomTests/st201503181307CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181307GO, "StateTests/RandomTests/st201503181307GO"} + declare_test!{StateTests_RandomTests_st201503181308GO, "StateTests/RandomTests/st201503181308GO"} + declare_test!{StateTests_RandomTests_st201503181309GO, "StateTests/RandomTests/st201503181309GO"} + declare_test!{StateTests_RandomTests_st201503181310GO, "StateTests/RandomTests/st201503181310GO"} + declare_test!{StateTests_RandomTests_st201503181311GO, "StateTests/RandomTests/st201503181311GO"} + declare_test!{StateTests_RandomTests_st201503181313GO, "StateTests/RandomTests/st201503181313GO"} + declare_test!{StateTests_RandomTests_st201503181314GO, "StateTests/RandomTests/st201503181314GO"} + declare_test!{StateTests_RandomTests_st201503181315CPPJIT, "StateTests/RandomTests/st201503181315CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181315GO, "StateTests/RandomTests/st201503181315GO"} + declare_test!{StateTests_RandomTests_st201503181316CPPJIT, "StateTests/RandomTests/st201503181316CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181316PYTHON, "StateTests/RandomTests/st201503181316PYTHON"} + declare_test!{StateTests_RandomTests_st201503181317GO, "StateTests/RandomTests/st201503181317GO"} + declare_test!{StateTests_RandomTests_st201503181318CPPJIT, "StateTests/RandomTests/st201503181318CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181318GO, "StateTests/RandomTests/st201503181318GO"} + declare_test!{StateTests_RandomTests_st201503181319GO, "StateTests/RandomTests/st201503181319GO"} + declare_test!{StateTests_RandomTests_st201503181319PYTHON, "StateTests/RandomTests/st201503181319PYTHON"} + declare_test!{StateTests_RandomTests_st201503181322GO, "StateTests/RandomTests/st201503181322GO"} + declare_test!{StateTests_RandomTests_st201503181323CPPJIT, "StateTests/RandomTests/st201503181323CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181323GO, "StateTests/RandomTests/st201503181323GO"} + declare_test!{StateTests_RandomTests_st201503181324GO, "StateTests/RandomTests/st201503181324GO"} + declare_test!{StateTests_RandomTests_st201503181325GO, "StateTests/RandomTests/st201503181325GO"} + declare_test!{StateTests_RandomTests_st201503181326CPPJIT, "StateTests/RandomTests/st201503181326CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181326GO, "StateTests/RandomTests/st201503181326GO"} + declare_test!{StateTests_RandomTests_st201503181327GO, "StateTests/RandomTests/st201503181327GO"} + declare_test!{StateTests_RandomTests_st201503181329CPPJIT, "StateTests/RandomTests/st201503181329CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181329GO, "StateTests/RandomTests/st201503181329GO"} + declare_test!{StateTests_RandomTests_st201503181330GO, "StateTests/RandomTests/st201503181330GO"} + declare_test!{StateTests_RandomTests_st201503181332GO, "StateTests/RandomTests/st201503181332GO"} + declare_test!{StateTests_RandomTests_st201503181333GO, "StateTests/RandomTests/st201503181333GO"} + declare_test!{StateTests_RandomTests_st201503181334GO, "StateTests/RandomTests/st201503181334GO"} + declare_test!{StateTests_RandomTests_st201503181336CPPJIT, "StateTests/RandomTests/st201503181336CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181337GO, "StateTests/RandomTests/st201503181337GO"} + declare_test!{StateTests_RandomTests_st201503181338GO, "StateTests/RandomTests/st201503181338GO"} + declare_test!{StateTests_RandomTests_st201503181339CPPJIT, "StateTests/RandomTests/st201503181339CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181339GO, "StateTests/RandomTests/st201503181339GO"} + declare_test!{StateTests_RandomTests_st201503181340GO, "StateTests/RandomTests/st201503181340GO"} + declare_test!{StateTests_RandomTests_st201503181341CPPJIT, "StateTests/RandomTests/st201503181341CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181342CPPJIT, "StateTests/RandomTests/st201503181342CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181342GO, "StateTests/RandomTests/st201503181342GO"} + declare_test!{StateTests_RandomTests_st201503181345GO, "StateTests/RandomTests/st201503181345GO"} + declare_test!{StateTests_RandomTests_st201503181346GO, "StateTests/RandomTests/st201503181346GO"} + declare_test!{StateTests_RandomTests_st201503181347CPPJIT, "StateTests/RandomTests/st201503181347CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181347GO, "StateTests/RandomTests/st201503181347GO"} + declare_test!{StateTests_RandomTests_st201503181347PYTHON, "StateTests/RandomTests/st201503181347PYTHON"} + declare_test!{StateTests_RandomTests_st201503181350CPPJIT, "StateTests/RandomTests/st201503181350CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181352GO, "StateTests/RandomTests/st201503181352GO"} + declare_test!{StateTests_RandomTests_st201503181353GO, "StateTests/RandomTests/st201503181353GO"} + declare_test!{StateTests_RandomTests_st201503181354CPPJIT, "StateTests/RandomTests/st201503181354CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181354GO, "StateTests/RandomTests/st201503181354GO"} + declare_test!{StateTests_RandomTests_st201503181355GO, "StateTests/RandomTests/st201503181355GO"} + declare_test!{StateTests_RandomTests_st201503181356CPPJIT, "StateTests/RandomTests/st201503181356CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181357CPPJIT, "StateTests/RandomTests/st201503181357CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181358CPPJIT, "StateTests/RandomTests/st201503181358CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181358GO, "StateTests/RandomTests/st201503181358GO"} + declare_test!{StateTests_RandomTests_st201503181359GO, "StateTests/RandomTests/st201503181359GO"} + declare_test!{StateTests_RandomTests_st201503181402CPPJIT, "StateTests/RandomTests/st201503181402CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181403GO, "StateTests/RandomTests/st201503181403GO"} + declare_test!{StateTests_RandomTests_st201503181406CPPJIT, "StateTests/RandomTests/st201503181406CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181406GO, "StateTests/RandomTests/st201503181406GO"} + declare_test!{StateTests_RandomTests_st201503181410GO, "StateTests/RandomTests/st201503181410GO"} + declare_test!{StateTests_RandomTests_st201503181412CPPJIT, "StateTests/RandomTests/st201503181412CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181413GO, "StateTests/RandomTests/st201503181413GO"} + declare_test!{StateTests_RandomTests_st201503181415GO, "StateTests/RandomTests/st201503181415GO"} + declare_test!{StateTests_RandomTests_st201503181416GO, "StateTests/RandomTests/st201503181416GO"} + declare_test!{StateTests_RandomTests_st201503181417CPPJIT, "StateTests/RandomTests/st201503181417CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181417GO, "StateTests/RandomTests/st201503181417GO"} + declare_test!{StateTests_RandomTests_st201503181418CPPJIT, "StateTests/RandomTests/st201503181418CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181422GO, "StateTests/RandomTests/st201503181422GO"} + declare_test!{StateTests_RandomTests_st201503181423CPPJIT, "StateTests/RandomTests/st201503181423CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181424GO, "StateTests/RandomTests/st201503181424GO"} + declare_test!{StateTests_RandomTests_st201503181426CPPJIT, "StateTests/RandomTests/st201503181426CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181426GO, "StateTests/RandomTests/st201503181426GO"} + declare_test!{StateTests_RandomTests_st201503181428GO, "StateTests/RandomTests/st201503181428GO"} + declare_test!{StateTests_RandomTests_st201503181430CPPJIT, "StateTests/RandomTests/st201503181430CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181435GO, "StateTests/RandomTests/st201503181435GO"} + declare_test!{StateTests_RandomTests_st201503181436GO, "StateTests/RandomTests/st201503181436GO"} + declare_test!{StateTests_RandomTests_st201503181437CPPJIT, "StateTests/RandomTests/st201503181437CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181437GO, "StateTests/RandomTests/st201503181437GO"} + declare_test!{StateTests_RandomTests_st201503181438CPPJIT, "StateTests/RandomTests/st201503181438CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181438GO, "StateTests/RandomTests/st201503181438GO"} + declare_test!{StateTests_RandomTests_st201503181439CPPJIT, "StateTests/RandomTests/st201503181439CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181439GO, "StateTests/RandomTests/st201503181439GO"} + declare_test!{StateTests_RandomTests_st201503181439PYTHON, "StateTests/RandomTests/st201503181439PYTHON"} + declare_test!{StateTests_RandomTests_st201503181440GO, "StateTests/RandomTests/st201503181440GO"} + declare_test!{StateTests_RandomTests_st201503181441GO, "StateTests/RandomTests/st201503181441GO"} + declare_test!{StateTests_RandomTests_st201503181442GO, "StateTests/RandomTests/st201503181442GO"} + declare_test!{StateTests_RandomTests_st201503181445CPPJIT, "StateTests/RandomTests/st201503181445CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181446GO, "StateTests/RandomTests/st201503181446GO"} + declare_test!{StateTests_RandomTests_st201503181447GO, "StateTests/RandomTests/st201503181447GO"} + declare_test!{StateTests_RandomTests_st201503181450GO, "StateTests/RandomTests/st201503181450GO"} + declare_test!{StateTests_RandomTests_st201503181451CPPJIT, "StateTests/RandomTests/st201503181451CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181453GO, "StateTests/RandomTests/st201503181453GO"} + declare_test!{StateTests_RandomTests_st201503181455GO, "StateTests/RandomTests/st201503181455GO"} + declare_test!{StateTests_RandomTests_st201503181456CPPJIT, "StateTests/RandomTests/st201503181456CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181457GO, "StateTests/RandomTests/st201503181457GO"} + declare_test!{StateTests_RandomTests_st201503181458GO, "StateTests/RandomTests/st201503181458GO"} + declare_test!{StateTests_RandomTests_st201503181459GO, "StateTests/RandomTests/st201503181459GO"} + declare_test!{StateTests_RandomTests_st201503181500GO, "StateTests/RandomTests/st201503181500GO"} + declare_test!{StateTests_RandomTests_st201503181501GO, "StateTests/RandomTests/st201503181501GO"} + declare_test!{StateTests_RandomTests_st201503181503GO, "StateTests/RandomTests/st201503181503GO"} + declare_test!{StateTests_RandomTests_st201503181504GO, "StateTests/RandomTests/st201503181504GO"} + declare_test!{StateTests_RandomTests_st201503181505GO, "StateTests/RandomTests/st201503181505GO"} + declare_test!{StateTests_RandomTests_st201503181506CPPJIT, "StateTests/RandomTests/st201503181506CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181507GO, "StateTests/RandomTests/st201503181507GO"} + declare_test!{StateTests_RandomTests_st201503181509CPPJIT, "StateTests/RandomTests/st201503181509CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181509GO, "StateTests/RandomTests/st201503181509GO"} + declare_test!{StateTests_RandomTests_st201503181510GO, "StateTests/RandomTests/st201503181510GO"} + declare_test!{StateTests_RandomTests_st201503181511GO, "StateTests/RandomTests/st201503181511GO"} + declare_test!{StateTests_RandomTests_st201503181512GO, "StateTests/RandomTests/st201503181512GO"} + declare_test!{StateTests_RandomTests_st201503181513CPPJIT, "StateTests/RandomTests/st201503181513CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181513GO, "StateTests/RandomTests/st201503181513GO"} + declare_test!{StateTests_RandomTests_st201503181514CPPJIT, "StateTests/RandomTests/st201503181514CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181514GO, "StateTests/RandomTests/st201503181514GO"} + declare_test!{StateTests_RandomTests_st201503181517CPPJIT, "StateTests/RandomTests/st201503181517CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181517GO, "StateTests/RandomTests/st201503181517GO"} + declare_test!{StateTests_RandomTests_st201503181519CPPJIT, "StateTests/RandomTests/st201503181519CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181519GO, "StateTests/RandomTests/st201503181519GO"} + declare_test!{StateTests_RandomTests_st201503181520CPPJIT, "StateTests/RandomTests/st201503181520CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181520GO, "StateTests/RandomTests/st201503181520GO"} + declare_test!{StateTests_RandomTests_st201503181521GO, "StateTests/RandomTests/st201503181521GO"} + declare_test!{StateTests_RandomTests_st201503181522GO, "StateTests/RandomTests/st201503181522GO"} + declare_test!{StateTests_RandomTests_st201503181524CPPJIT, "StateTests/RandomTests/st201503181524CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181524GO, "StateTests/RandomTests/st201503181524GO"} + declare_test!{StateTests_RandomTests_st201503181526GO, "StateTests/RandomTests/st201503181526GO"} + declare_test!{StateTests_RandomTests_st201503181527GO, "StateTests/RandomTests/st201503181527GO"} + declare_test!{StateTests_RandomTests_st201503181528CPPJIT, "StateTests/RandomTests/st201503181528CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181528GO, "StateTests/RandomTests/st201503181528GO"} + declare_test!{StateTests_RandomTests_st201503181528PYTHON, "StateTests/RandomTests/st201503181528PYTHON"} + declare_test!{StateTests_RandomTests_st201503181529GO, "StateTests/RandomTests/st201503181529GO"} + declare_test!{StateTests_RandomTests_st201503181531CPPJIT, "StateTests/RandomTests/st201503181531CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181533GO, "StateTests/RandomTests/st201503181533GO"} + declare_test!{StateTests_RandomTests_st201503181534CPPJIT, "StateTests/RandomTests/st201503181534CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181534GO, "StateTests/RandomTests/st201503181534GO"} + declare_test!{StateTests_RandomTests_st201503181536CPPJIT, "StateTests/RandomTests/st201503181536CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181536GO, "StateTests/RandomTests/st201503181536GO"} + declare_test!{StateTests_RandomTests_st201503181537GO, "StateTests/RandomTests/st201503181537GO"} + declare_test!{StateTests_RandomTests_st201503181538GO, "StateTests/RandomTests/st201503181538GO"} + declare_test!{StateTests_RandomTests_st201503181539GO, "StateTests/RandomTests/st201503181539GO"} + declare_test!{StateTests_RandomTests_st201503181540CPPJIT, "StateTests/RandomTests/st201503181540CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181540PYTHON, "StateTests/RandomTests/st201503181540PYTHON"} + declare_test!{StateTests_RandomTests_st201503181543GO, "StateTests/RandomTests/st201503181543GO"} + declare_test!{StateTests_RandomTests_st201503181544CPPJIT, "StateTests/RandomTests/st201503181544CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181544GO, "StateTests/RandomTests/st201503181544GO"} + declare_test!{StateTests_RandomTests_st201503181547GO, "StateTests/RandomTests/st201503181547GO"} + declare_test!{StateTests_RandomTests_st201503181548CPPJIT, "StateTests/RandomTests/st201503181548CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181548GO, "StateTests/RandomTests/st201503181548GO"} + declare_test!{StateTests_RandomTests_st201503181551GO, "StateTests/RandomTests/st201503181551GO"} + declare_test!{StateTests_RandomTests_st201503181552CPPJIT, "StateTests/RandomTests/st201503181552CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181553GO, "StateTests/RandomTests/st201503181553GO"} + declare_test!{StateTests_RandomTests_st201503181555CPPJIT, "StateTests/RandomTests/st201503181555CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181555GO, "StateTests/RandomTests/st201503181555GO"} + declare_test!{StateTests_RandomTests_st201503181557GO, "StateTests/RandomTests/st201503181557GO"} + declare_test!{StateTests_RandomTests_st201503181559GO, "StateTests/RandomTests/st201503181559GO"} + declare_test!{StateTests_RandomTests_st201503181601CPPJIT, "StateTests/RandomTests/st201503181601CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181601GO, "StateTests/RandomTests/st201503181601GO"} + declare_test!{StateTests_RandomTests_st201503181602GO, "StateTests/RandomTests/st201503181602GO"} + declare_test!{StateTests_RandomTests_st201503181603GO, "StateTests/RandomTests/st201503181603GO"} + declare_test!{StateTests_RandomTests_st201503181604GO, "StateTests/RandomTests/st201503181604GO"} + declare_test!{StateTests_RandomTests_st201503181605GO, "StateTests/RandomTests/st201503181605GO"} + declare_test!{StateTests_RandomTests_st201503181606GO, "StateTests/RandomTests/st201503181606GO"} + declare_test!{StateTests_RandomTests_st201503181607GO, "StateTests/RandomTests/st201503181607GO"} + declare_test!{StateTests_RandomTests_st201503181608CPPJIT, "StateTests/RandomTests/st201503181608CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181608GO, "StateTests/RandomTests/st201503181608GO"} + declare_test!{StateTests_RandomTests_st201503181609GO, "StateTests/RandomTests/st201503181609GO"} + declare_test!{StateTests_RandomTests_st201503181610CPPJIT, "StateTests/RandomTests/st201503181610CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181610GO, "StateTests/RandomTests/st201503181610GO"} + declare_test!{StateTests_RandomTests_st201503181611CPPJIT, "StateTests/RandomTests/st201503181611CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181611GO, "StateTests/RandomTests/st201503181611GO"} + declare_test!{StateTests_RandomTests_st201503181612GO, "StateTests/RandomTests/st201503181612GO"} + declare_test!{StateTests_RandomTests_st201503181614CPPJIT, "StateTests/RandomTests/st201503181614CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181614GO, "StateTests/RandomTests/st201503181614GO"} + declare_test!{StateTests_RandomTests_st201503181616CPPJIT, "StateTests/RandomTests/st201503181616CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181616GO, "StateTests/RandomTests/st201503181616GO"} + declare_test!{StateTests_RandomTests_st201503181617GO, "StateTests/RandomTests/st201503181617GO"} + declare_test!{StateTests_RandomTests_st201503181618GO, "StateTests/RandomTests/st201503181618GO"} + declare_test!{StateTests_RandomTests_st201503181619GO, "StateTests/RandomTests/st201503181619GO"} + declare_test!{StateTests_RandomTests_st201503181620CPPJIT, "StateTests/RandomTests/st201503181620CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181620GO, "StateTests/RandomTests/st201503181620GO"} + declare_test!{StateTests_RandomTests_st201503181621GO, "StateTests/RandomTests/st201503181621GO"} + declare_test!{StateTests_RandomTests_st201503181625GO, "StateTests/RandomTests/st201503181625GO"} + declare_test!{StateTests_RandomTests_st201503181626CPPJIT, "StateTests/RandomTests/st201503181626CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181626GO, "StateTests/RandomTests/st201503181626GO"} + declare_test!{StateTests_RandomTests_st201503181627GO, "StateTests/RandomTests/st201503181627GO"} + declare_test!{StateTests_RandomTests_st201503181628GO, "StateTests/RandomTests/st201503181628GO"} + declare_test!{StateTests_RandomTests_st201503181629GO, "StateTests/RandomTests/st201503181629GO"} + declare_test!{StateTests_RandomTests_st201503181630CPPJIT, "StateTests/RandomTests/st201503181630CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181630GO, "StateTests/RandomTests/st201503181630GO"} + declare_test!{StateTests_RandomTests_st201503181630PYTHON, "StateTests/RandomTests/st201503181630PYTHON"} + declare_test!{StateTests_RandomTests_st201503181632GO, "StateTests/RandomTests/st201503181632GO"} + declare_test!{StateTests_RandomTests_st201503181634CPPJIT, "StateTests/RandomTests/st201503181634CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181635GO, "StateTests/RandomTests/st201503181635GO"} + declare_test!{StateTests_RandomTests_st201503181636GO, "StateTests/RandomTests/st201503181636GO"} + declare_test!{StateTests_RandomTests_st201503181638GO, "StateTests/RandomTests/st201503181638GO"} + declare_test!{StateTests_RandomTests_st201503181639CPPJIT, "StateTests/RandomTests/st201503181639CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181641GO, "StateTests/RandomTests/st201503181641GO"} + declare_test!{StateTests_RandomTests_st201503181645GO, "StateTests/RandomTests/st201503181645GO"} + declare_test!{StateTests_RandomTests_st201503181646GO, "StateTests/RandomTests/st201503181646GO"} + declare_test!{StateTests_RandomTests_st201503181647CPPJIT, "StateTests/RandomTests/st201503181647CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181649CPPJIT, "StateTests/RandomTests/st201503181649CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181650GO, "StateTests/RandomTests/st201503181650GO"} + declare_test!{StateTests_RandomTests_st201503181652CPPJIT, "StateTests/RandomTests/st201503181652CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181653GO, "StateTests/RandomTests/st201503181653GO"} + declare_test!{StateTests_RandomTests_st201503181654GO, "StateTests/RandomTests/st201503181654GO"} + declare_test!{StateTests_RandomTests_st201503181655CPPJIT, "StateTests/RandomTests/st201503181655CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181655GO, "StateTests/RandomTests/st201503181655GO"} + declare_test!{StateTests_RandomTests_st201503181656CPPJIT, "StateTests/RandomTests/st201503181656CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181656GO, "StateTests/RandomTests/st201503181656GO"} + declare_test!{StateTests_RandomTests_st201503181657GO, "StateTests/RandomTests/st201503181657GO"} + declare_test!{StateTests_RandomTests_st201503181658GO, "StateTests/RandomTests/st201503181658GO"} + declare_test!{StateTests_RandomTests_st201503181700GO, "StateTests/RandomTests/st201503181700GO"} + declare_test!{StateTests_RandomTests_st201503181702GO, "StateTests/RandomTests/st201503181702GO"} + declare_test!{StateTests_RandomTests_st201503181703CPPJIT, "StateTests/RandomTests/st201503181703CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181703GO, "StateTests/RandomTests/st201503181703GO"} + declare_test!{StateTests_RandomTests_st201503181704GO, "StateTests/RandomTests/st201503181704GO"} + declare_test!{StateTests_RandomTests_st201503181706GO, "StateTests/RandomTests/st201503181706GO"} + declare_test!{StateTests_RandomTests_st201503181709GO, "StateTests/RandomTests/st201503181709GO"} + declare_test!{StateTests_RandomTests_st201503181711CPPJIT, "StateTests/RandomTests/st201503181711CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181711GO, "StateTests/RandomTests/st201503181711GO"} + declare_test!{StateTests_RandomTests_st201503181713CPPJIT, "StateTests/RandomTests/st201503181713CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181713GO, "StateTests/RandomTests/st201503181713GO"} + declare_test!{StateTests_RandomTests_st201503181714GO, "StateTests/RandomTests/st201503181714GO"} + declare_test!{StateTests_RandomTests_st201503181715CPPJIT, "StateTests/RandomTests/st201503181715CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181715GO, "StateTests/RandomTests/st201503181715GO"} + declare_test!{StateTests_RandomTests_st201503181716GO, "StateTests/RandomTests/st201503181716GO"} + declare_test!{StateTests_RandomTests_st201503181717GO, "StateTests/RandomTests/st201503181717GO"} + declare_test!{StateTests_RandomTests_st201503181720CPPJIT, "StateTests/RandomTests/st201503181720CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181722GO, "StateTests/RandomTests/st201503181722GO"} + declare_test!{StateTests_RandomTests_st201503181723CPPJIT, "StateTests/RandomTests/st201503181723CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181723GO, "StateTests/RandomTests/st201503181723GO"} + declare_test!{StateTests_RandomTests_st201503181724CPPJIT, "StateTests/RandomTests/st201503181724CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181724GO, "StateTests/RandomTests/st201503181724GO"} + declare_test!{StateTests_RandomTests_st201503181725GO, "StateTests/RandomTests/st201503181725GO"} + declare_test!{StateTests_RandomTests_st201503181728GO, "StateTests/RandomTests/st201503181728GO"} + declare_test!{StateTests_RandomTests_st201503181729GO, "StateTests/RandomTests/st201503181729GO"} + declare_test!{StateTests_RandomTests_st201503181730GO, "StateTests/RandomTests/st201503181730GO"} + declare_test!{StateTests_RandomTests_st201503181731CPPJIT, "StateTests/RandomTests/st201503181731CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181732GO, "StateTests/RandomTests/st201503181732GO"} + declare_test!{StateTests_RandomTests_st201503181734CPPJIT, "StateTests/RandomTests/st201503181734CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181734GO, "StateTests/RandomTests/st201503181734GO"} + declare_test!{StateTests_RandomTests_st201503181735GO, "StateTests/RandomTests/st201503181735GO"} + declare_test!{StateTests_RandomTests_st201503181737CPPJIT, "StateTests/RandomTests/st201503181737CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181737GO, "StateTests/RandomTests/st201503181737GO"} + declare_test!{StateTests_RandomTests_st201503181738CPPJIT, "StateTests/RandomTests/st201503181738CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181738GO, "StateTests/RandomTests/st201503181738GO"} + declare_test!{StateTests_RandomTests_st201503181739GO, "StateTests/RandomTests/st201503181739GO"} + declare_test!{StateTests_RandomTests_st201503181740CPPJIT, "StateTests/RandomTests/st201503181740CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181740GO, "StateTests/RandomTests/st201503181740GO"} + declare_test!{StateTests_RandomTests_st201503181742CPPJIT, "StateTests/RandomTests/st201503181742CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181743GO, "StateTests/RandomTests/st201503181743GO"} + declare_test!{StateTests_RandomTests_st201503181744GO, "StateTests/RandomTests/st201503181744GO"} + declare_test!{StateTests_RandomTests_st201503181745CPPJIT, "StateTests/RandomTests/st201503181745CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181746GO, "StateTests/RandomTests/st201503181746GO"} + declare_test!{StateTests_RandomTests_st201503181747GO, "StateTests/RandomTests/st201503181747GO"} + declare_test!{StateTests_RandomTests_st201503181748GO, "StateTests/RandomTests/st201503181748GO"} + declare_test!{StateTests_RandomTests_st201503181749GO, "StateTests/RandomTests/st201503181749GO"} + declare_test!{StateTests_RandomTests_st201503181750CPPJIT, "StateTests/RandomTests/st201503181750CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181750GO, "StateTests/RandomTests/st201503181750GO"} + declare_test!{StateTests_RandomTests_st201503181752GO, "StateTests/RandomTests/st201503181752GO"} + declare_test!{StateTests_RandomTests_st201503181753CPPJIT, "StateTests/RandomTests/st201503181753CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181754CPPJIT, "StateTests/RandomTests/st201503181754CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181754GO, "StateTests/RandomTests/st201503181754GO"} + declare_test!{StateTests_RandomTests_st201503181755CPPJIT, "StateTests/RandomTests/st201503181755CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181755GO, "StateTests/RandomTests/st201503181755GO"} + declare_test!{StateTests_RandomTests_st201503181756GO, "StateTests/RandomTests/st201503181756GO"} + declare_test!{StateTests_RandomTests_st201503181757CPPJIT, "StateTests/RandomTests/st201503181757CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181757GO, "StateTests/RandomTests/st201503181757GO"} + declare_test!{StateTests_RandomTests_st201503181759GO, "StateTests/RandomTests/st201503181759GO"} + declare_test!{StateTests_RandomTests_st201503181800GO, "StateTests/RandomTests/st201503181800GO"} + declare_test!{StateTests_RandomTests_st201503181801GO, "StateTests/RandomTests/st201503181801GO"} + declare_test!{StateTests_RandomTests_st201503181802GO, "StateTests/RandomTests/st201503181802GO"} + declare_test!{StateTests_RandomTests_st201503181803CPPJIT, "StateTests/RandomTests/st201503181803CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181803GO, "StateTests/RandomTests/st201503181803GO"} + declare_test!{StateTests_RandomTests_st201503181804GO, "StateTests/RandomTests/st201503181804GO"} + declare_test!{StateTests_RandomTests_st201503181806GO, "StateTests/RandomTests/st201503181806GO"} + declare_test!{StateTests_RandomTests_st201503181808GO, "StateTests/RandomTests/st201503181808GO"} + declare_test!{StateTests_RandomTests_st201503181809CPPJIT, "StateTests/RandomTests/st201503181809CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181812CPPJIT, "StateTests/RandomTests/st201503181812CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181812GO, "StateTests/RandomTests/st201503181812GO"} + declare_test!{StateTests_RandomTests_st201503181814CPPJIT, "StateTests/RandomTests/st201503181814CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181815GO, "StateTests/RandomTests/st201503181815GO"} + declare_test!{StateTests_RandomTests_st201503181816CPPJIT, "StateTests/RandomTests/st201503181816CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181817CPPJIT, "StateTests/RandomTests/st201503181817CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181819GO, "StateTests/RandomTests/st201503181819GO"} + declare_test!{StateTests_RandomTests_st201503181821GO, "StateTests/RandomTests/st201503181821GO"} + declare_test!{StateTests_RandomTests_st201503181822GO, "StateTests/RandomTests/st201503181822GO"} + declare_test!{StateTests_RandomTests_st201503181823GO, "StateTests/RandomTests/st201503181823GO"} + declare_test!{StateTests_RandomTests_st201503181824GO, "StateTests/RandomTests/st201503181824GO"} + declare_test!{StateTests_RandomTests_st201503181825GO, "StateTests/RandomTests/st201503181825GO"} + declare_test!{StateTests_RandomTests_st201503181829GO, "StateTests/RandomTests/st201503181829GO"} + declare_test!{StateTests_RandomTests_st201503181830CPPJIT, "StateTests/RandomTests/st201503181830CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181833GO, "StateTests/RandomTests/st201503181833GO"} + declare_test!{StateTests_RandomTests_st201503181834CPPJIT, "StateTests/RandomTests/st201503181834CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181834GO, "StateTests/RandomTests/st201503181834GO"} + declare_test!{StateTests_RandomTests_st201503181837GO, "StateTests/RandomTests/st201503181837GO"} + declare_test!{StateTests_RandomTests_st201503181840GO, "StateTests/RandomTests/st201503181840GO"} + declare_test!{StateTests_RandomTests_st201503181842GO, "StateTests/RandomTests/st201503181842GO"} + declare_test!{StateTests_RandomTests_st201503181843GO, "StateTests/RandomTests/st201503181843GO"} + declare_test!{StateTests_RandomTests_st201503181844GO, "StateTests/RandomTests/st201503181844GO"} + declare_test!{StateTests_RandomTests_st201503181845GO, "StateTests/RandomTests/st201503181845GO"} + declare_test!{StateTests_RandomTests_st201503181846GO, "StateTests/RandomTests/st201503181846GO"} + declare_test!{StateTests_RandomTests_st201503181847GO, "StateTests/RandomTests/st201503181847GO"} + declare_test!{StateTests_RandomTests_st201503181848GO, "StateTests/RandomTests/st201503181848GO"} + declare_test!{StateTests_RandomTests_st201503181849GO, "StateTests/RandomTests/st201503181849GO"} + declare_test!{StateTests_RandomTests_st201503181850GO, "StateTests/RandomTests/st201503181850GO"} + declare_test!{StateTests_RandomTests_st201503181851CPPJIT, "StateTests/RandomTests/st201503181851CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181851GO, "StateTests/RandomTests/st201503181851GO"} + declare_test!{StateTests_RandomTests_st201503181852CPPJIT, "StateTests/RandomTests/st201503181852CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181854GO, "StateTests/RandomTests/st201503181854GO"} + declare_test!{StateTests_RandomTests_st201503181855CPPJIT, "StateTests/RandomTests/st201503181855CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181857PYTHON, "StateTests/RandomTests/st201503181857PYTHON"} + declare_test!{StateTests_RandomTests_st201503181859GO, "StateTests/RandomTests/st201503181859GO"} + declare_test!{StateTests_RandomTests_st201503181900GO, "StateTests/RandomTests/st201503181900GO"} + declare_test!{StateTests_RandomTests_st201503181903GO, "StateTests/RandomTests/st201503181903GO"} + declare_test!{StateTests_RandomTests_st201503181904GO, "StateTests/RandomTests/st201503181904GO"} + declare_test!{StateTests_RandomTests_st201503181906GO, "StateTests/RandomTests/st201503181906GO"} + declare_test!{StateTests_RandomTests_st201503181907GO, "StateTests/RandomTests/st201503181907GO"} + declare_test!{StateTests_RandomTests_st201503181910GO, "StateTests/RandomTests/st201503181910GO"} + declare_test!{StateTests_RandomTests_st201503181915GO, "StateTests/RandomTests/st201503181915GO"} + declare_test!{StateTests_RandomTests_st201503181919CPPJIT, "StateTests/RandomTests/st201503181919CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181919PYTHON, "StateTests/RandomTests/st201503181919PYTHON"} + declare_test!{StateTests_RandomTests_st201503181920GO, "StateTests/RandomTests/st201503181920GO"} + declare_test!{StateTests_RandomTests_st201503181922GO, "StateTests/RandomTests/st201503181922GO"} + declare_test!{StateTests_RandomTests_st201503181926GO, "StateTests/RandomTests/st201503181926GO"} + declare_test!{StateTests_RandomTests_st201503181929GO, "StateTests/RandomTests/st201503181929GO"} + declare_test!{StateTests_RandomTests_st201503181931CPPJIT, "StateTests/RandomTests/st201503181931CPPJIT"} + declare_test!{StateTests_RandomTests_st201503181931GO, "StateTests/RandomTests/st201503181931GO"} + declare_test!{StateTests_RandomTests_st201503181931PYTHON, "StateTests/RandomTests/st201503181931PYTHON"} + declare_test!{StateTests_RandomTests_st201503191646GO, "StateTests/RandomTests/st201503191646GO"} + declare_test!{StateTests_RandomTests_st201503200837JS, "StateTests/RandomTests/st201503200837JS"} + declare_test!{StateTests_RandomTests_st201503200838JS, "StateTests/RandomTests/st201503200838JS"} + declare_test!{StateTests_RandomTests_st201503200841JS, "StateTests/RandomTests/st201503200841JS"} + declare_test!{StateTests_RandomTests_st201503200848JS, "StateTests/RandomTests/st201503200848JS"} + declare_test!{StateTests_RandomTests_st201503240609JS, "StateTests/RandomTests/st201503240609JS"} + declare_test!{StateTests_RandomTests_st201503302200JS, "StateTests/RandomTests/st201503302200JS"} + declare_test!{StateTests_RandomTests_st201503302202JS, "StateTests/RandomTests/st201503302202JS"} + declare_test!{StateTests_RandomTests_st201503302206JS, "StateTests/RandomTests/st201503302206JS"} + declare_test!{StateTests_RandomTests_st201503302208JS, "StateTests/RandomTests/st201503302208JS"} + declare_test!{StateTests_RandomTests_st201503302210JS, "StateTests/RandomTests/st201503302210JS"} + declare_test!{StateTests_RandomTests_st201503302211JS, "StateTests/RandomTests/st201503302211JS"} + declare_test!{StateTests_RandomTests_st201504011535GO, "StateTests/RandomTests/st201504011535GO"} + declare_test!{StateTests_RandomTests_st201504011536GO, "StateTests/RandomTests/st201504011536GO"} + declare_test!{StateTests_RandomTests_st201504011547GO, "StateTests/RandomTests/st201504011547GO"} + declare_test!{StateTests_RandomTests_st201504011916JS, "StateTests/RandomTests/st201504011916JS"} + declare_test!{StateTests_RandomTests_st201504012130JS, "StateTests/RandomTests/st201504012130JS"} + declare_test!{StateTests_RandomTests_st201504012259JS, "StateTests/RandomTests/st201504012259JS"} + declare_test!{StateTests_RandomTests_st201504012359JS, "StateTests/RandomTests/st201504012359JS"} + declare_test!{StateTests_RandomTests_st201504020305JS, "StateTests/RandomTests/st201504020305JS"} + declare_test!{StateTests_RandomTests_st201504020400JS, "StateTests/RandomTests/st201504020400JS"} + declare_test!{StateTests_RandomTests_st201504020428JS, "StateTests/RandomTests/st201504020428JS"} + declare_test!{StateTests_RandomTests_st201504020431JS, "StateTests/RandomTests/st201504020431JS"} + declare_test!{StateTests_RandomTests_st201504020444JS, "StateTests/RandomTests/st201504020444JS"} + declare_test!{StateTests_RandomTests_st201504020538JS, "StateTests/RandomTests/st201504020538JS"} + declare_test!{StateTests_RandomTests_st201504020639JS, "StateTests/RandomTests/st201504020639JS"} + declare_test!{StateTests_RandomTests_st201504020836JS, "StateTests/RandomTests/st201504020836JS"} + declare_test!{StateTests_RandomTests_st201504020910JS, "StateTests/RandomTests/st201504020910JS"} + declare_test!{StateTests_RandomTests_st201504021057JS, "StateTests/RandomTests/st201504021057JS"} + declare_test!{StateTests_RandomTests_st201504021104JS, "StateTests/RandomTests/st201504021104JS"} + declare_test!{StateTests_RandomTests_st201504021237CPPJIT, "StateTests/RandomTests/st201504021237CPPJIT"} + declare_test!{StateTests_RandomTests_st201504021237GO, "StateTests/RandomTests/st201504021237GO"} + declare_test!{StateTests_RandomTests_st201504021237JS, "StateTests/RandomTests/st201504021237JS"} + declare_test!{StateTests_RandomTests_st201504021237PYTHON, "StateTests/RandomTests/st201504021237PYTHON"} + declare_test!{StateTests_RandomTests_st201504021949JS, "StateTests/RandomTests/st201504021949JS"} + declare_test!{StateTests_RandomTests_st201504022003CPPJIT, "StateTests/RandomTests/st201504022003CPPJIT"} + declare_test!{StateTests_RandomTests_st201504022124JS, "StateTests/RandomTests/st201504022124JS"} + declare_test!{StateTests_RandomTests_st201504030138JS, "StateTests/RandomTests/st201504030138JS"} + declare_test!{StateTests_RandomTests_st201504030646JS, "StateTests/RandomTests/st201504030646JS"} + declare_test!{StateTests_RandomTests_st201504030709JS, "StateTests/RandomTests/st201504030709JS"} + declare_test!{StateTests_RandomTests_st201504031133JS, "StateTests/RandomTests/st201504031133JS"} + declare_test!{StateTests_RandomTests_st201504031446JS, "StateTests/RandomTests/st201504031446JS"} + declare_test!{StateTests_RandomTests_st201504031841JS, "StateTests/RandomTests/st201504031841JS"} + declare_test!{StateTests_RandomTests_st201504041605JS, "StateTests/RandomTests/st201504041605JS"} + declare_test!{StateTests_RandomTests_st201504042052JS, "StateTests/RandomTests/st201504042052JS"} + declare_test!{StateTests_RandomTests_st201504042226CPPJIT, "StateTests/RandomTests/st201504042226CPPJIT"} + declare_test!{StateTests_RandomTests_st201504042355CPPJIT, "StateTests/RandomTests/st201504042355CPPJIT"} + declare_test!{StateTests_RandomTests_st201504050059JS, "StateTests/RandomTests/st201504050059JS"} + declare_test!{StateTests_RandomTests_st201504050733JS, "StateTests/RandomTests/st201504050733JS"} + declare_test!{StateTests_RandomTests_st201504051540JS, "StateTests/RandomTests/st201504051540JS"} + declare_test!{StateTests_RandomTests_st201504051944CPPJIT, "StateTests/RandomTests/st201504051944CPPJIT"} + declare_test!{StateTests_RandomTests_st201504052008CPPJIT, "StateTests/RandomTests/st201504052008CPPJIT"} + declare_test!{StateTests_RandomTests_st201504052014GO, "StateTests/RandomTests/st201504052014GO"} + declare_test!{StateTests_RandomTests_st201504052031CPPJIT, "StateTests/RandomTests/st201504052031CPPJIT"} + declare_test!{StateTests_RandomTests_st201504060057CPPJIT, "StateTests/RandomTests/st201504060057CPPJIT"} + declare_test!{StateTests_RandomTests_st201504060418CPPJIT, "StateTests/RandomTests/st201504060418CPPJIT"} + declare_test!{StateTests_RandomTests_st201504061106CPPJIT, "StateTests/RandomTests/st201504061106CPPJIT"} + declare_test!{StateTests_RandomTests_st201504061134CPPJIT, "StateTests/RandomTests/st201504061134CPPJIT"} + declare_test!{StateTests_RandomTests_st201504062033CPPJIT, "StateTests/RandomTests/st201504062033CPPJIT"} + declare_test!{StateTests_RandomTests_st201504062046CPPJIT, "StateTests/RandomTests/st201504062046CPPJIT"} + declare_test!{StateTests_RandomTests_st201504062314CPPJIT, "StateTests/RandomTests/st201504062314CPPJIT"} + declare_test!{StateTests_RandomTests_st201504070746JS, "StateTests/RandomTests/st201504070746JS"} + declare_test!{StateTests_RandomTests_st201504070816CPPJIT, "StateTests/RandomTests/st201504070816CPPJIT"} + declare_test!{StateTests_RandomTests_st201504070836CPPJIT, "StateTests/RandomTests/st201504070836CPPJIT"} + declare_test!{StateTests_RandomTests_st201504070839CPPJIT, "StateTests/RandomTests/st201504070839CPPJIT"} + declare_test!{StateTests_RandomTests_st201504071041CPPJIT, "StateTests/RandomTests/st201504071041CPPJIT"} + declare_test!{StateTests_RandomTests_st201504071056CPPJIT, "StateTests/RandomTests/st201504071056CPPJIT"} + declare_test!{StateTests_RandomTests_st201504071621CPPJIT, "StateTests/RandomTests/st201504071621CPPJIT"} + declare_test!{StateTests_RandomTests_st201504071653CPPJIT, "StateTests/RandomTests/st201504071653CPPJIT"} + declare_test!{StateTests_RandomTests_st201504071750CPPJIT, "StateTests/RandomTests/st201504071750CPPJIT"} + declare_test!{StateTests_RandomTests_st201504071905CPPJIT, "StateTests/RandomTests/st201504071905CPPJIT"} + declare_test!{StateTests_RandomTests_st201504080454CPPJIT, "StateTests/RandomTests/st201504080454CPPJIT"} + declare_test!{StateTests_RandomTests_st201504080457CPPJIT, "StateTests/RandomTests/st201504080457CPPJIT"} + declare_test!{StateTests_RandomTests_st201504080650CPPJIT, "StateTests/RandomTests/st201504080650CPPJIT"} + declare_test!{StateTests_RandomTests_st201504080840CPPJIT, "StateTests/RandomTests/st201504080840CPPJIT"} + declare_test!{StateTests_RandomTests_st201504080948CPPJIT, "StateTests/RandomTests/st201504080948CPPJIT"} + declare_test!{StateTests_RandomTests_st201504081100CPPJIT, "StateTests/RandomTests/st201504081100CPPJIT"} + declare_test!{StateTests_RandomTests_st201504081134CPPJIT, "StateTests/RandomTests/st201504081134CPPJIT"} + declare_test!{StateTests_RandomTests_st201504081138CPPJIT, "StateTests/RandomTests/st201504081138CPPJIT"} + declare_test!{StateTests_RandomTests_st201504081611CPPJIT, "StateTests/RandomTests/st201504081611CPPJIT"} + declare_test!{StateTests_RandomTests_st201504081841JAVA, "StateTests/RandomTests/st201504081841JAVA"} + declare_test!{StateTests_RandomTests_st201504081842JAVA, "StateTests/RandomTests/st201504081842JAVA"} + declare_test!{StateTests_RandomTests_st201504081843JAVA, "StateTests/RandomTests/st201504081843JAVA"} + declare_test!{StateTests_RandomTests_st201504081928CPPJIT, "StateTests/RandomTests/st201504081928CPPJIT"} + declare_test!{StateTests_RandomTests_st201504081953JAVA, "StateTests/RandomTests/st201504081953JAVA"} + declare_test!{StateTests_RandomTests_st201504081954JAVA, "StateTests/RandomTests/st201504081954JAVA"} + declare_test!{StateTests_RandomTests_st201504081955JAVA, "StateTests/RandomTests/st201504081955JAVA"} + declare_test!{StateTests_RandomTests_st201504081956JAVA, "StateTests/RandomTests/st201504081956JAVA"} + declare_test!{StateTests_RandomTests_st201504081957JAVA, "StateTests/RandomTests/st201504081957JAVA"} + declare_test!{StateTests_RandomTests_st201504082000JAVA, "StateTests/RandomTests/st201504082000JAVA"} + declare_test!{StateTests_RandomTests_st201504082001JAVA, "StateTests/RandomTests/st201504082001JAVA"} + declare_test!{StateTests_RandomTests_st201504082002JAVA, "StateTests/RandomTests/st201504082002JAVA"} + declare_test!{StateTests_RandomTests_st201504090553CPPJIT, "StateTests/RandomTests/st201504090553CPPJIT"} + declare_test!{StateTests_RandomTests_st201504090657CPPJIT, "StateTests/RandomTests/st201504090657CPPJIT"} + declare_test!{StateTests_RandomTests_st201504091403CPPJIT, "StateTests/RandomTests/st201504091403CPPJIT"} + declare_test!{StateTests_RandomTests_st201504091641CPPJIT, "StateTests/RandomTests/st201504091641CPPJIT"} + declare_test!{StateTests_RandomTests_st201504092303CPPJIT, "StateTests/RandomTests/st201504092303CPPJIT"} + declare_test!{StateTests_RandomTests_st201504100125CPPJIT, "StateTests/RandomTests/st201504100125CPPJIT"} + declare_test!{StateTests_RandomTests_st201504100215CPPJIT, "StateTests/RandomTests/st201504100215CPPJIT"} + declare_test!{StateTests_RandomTests_st201504100226PYTHON, "StateTests/RandomTests/st201504100226PYTHON"} + declare_test!{StateTests_RandomTests_st201504100308CPPJIT, "StateTests/RandomTests/st201504100308CPPJIT"} + declare_test!{StateTests_RandomTests_st201504100337CPPJIT, "StateTests/RandomTests/st201504100337CPPJIT"} + declare_test!{StateTests_RandomTests_st201504100341CPPJIT, "StateTests/RandomTests/st201504100341CPPJIT"} + declare_test!{StateTests_RandomTests_st201504101009CPPJIT, "StateTests/RandomTests/st201504101009CPPJIT"} + declare_test!{StateTests_RandomTests_st201504101150CPPJIT, "StateTests/RandomTests/st201504101150CPPJIT"} + declare_test!{StateTests_RandomTests_st201504101223CPPJIT, "StateTests/RandomTests/st201504101223CPPJIT"} + declare_test!{StateTests_RandomTests_st201504101338CPPJIT, "StateTests/RandomTests/st201504101338CPPJIT"} + declare_test!{StateTests_RandomTests_st201504101754PYTHON, "StateTests/RandomTests/st201504101754PYTHON"} + declare_test!{StateTests_RandomTests_st201504111554CPPJIT, "StateTests/RandomTests/st201504111554CPPJIT"} + declare_test!{StateTests_RandomTests_st201504130653JS, "StateTests/RandomTests/st201504130653JS"} + declare_test!{StateTests_RandomTests_st201504131821CPPJIT, "StateTests/RandomTests/st201504131821CPPJIT"} + declare_test!{StateTests_RandomTests_st201504140229CPPJIT, "StateTests/RandomTests/st201504140229CPPJIT"} + declare_test!{StateTests_RandomTests_st201504140236CPPJIT, "StateTests/RandomTests/st201504140236CPPJIT"} + declare_test!{StateTests_RandomTests_st201504140359CPPJIT, "StateTests/RandomTests/st201504140359CPPJIT"} + declare_test!{StateTests_RandomTests_st201504140750CPPJIT, "StateTests/RandomTests/st201504140750CPPJIT"} + declare_test!{StateTests_RandomTests_st201504140818CPPJIT, "StateTests/RandomTests/st201504140818CPPJIT"} + declare_test!{StateTests_RandomTests_st201504140900CPPJIT, "StateTests/RandomTests/st201504140900CPPJIT"} + declare_test!{StateTests_RandomTests_st201504150854CPPJIT, "StateTests/RandomTests/st201504150854CPPJIT"} + declare_test!{StateTests_RandomTests_st201504151057CPPJIT, "StateTests/RandomTests/st201504151057CPPJIT"} + declare_test!{StateTests_RandomTests_st201504202124CPPJIT, "StateTests/RandomTests/st201504202124CPPJIT"} + declare_test!{StateTests_RandomTests_st201504210245CPPJIT, "StateTests/RandomTests/st201504210245CPPJIT"} + declare_test!{StateTests_RandomTests_st201504210957CPPJIT, "StateTests/RandomTests/st201504210957CPPJIT"} + declare_test!{StateTests_RandomTests_st201504211739CPPJIT, "StateTests/RandomTests/st201504211739CPPJIT"} + declare_test!{StateTests_RandomTests_st201504212038CPPJIT, "StateTests/RandomTests/st201504212038CPPJIT"} + declare_test!{StateTests_RandomTests_st201504230729CPPJIT, "StateTests/RandomTests/st201504230729CPPJIT"} + declare_test!{StateTests_RandomTests_st201504231639CPPJIT, "StateTests/RandomTests/st201504231639CPPJIT"} + declare_test!{StateTests_RandomTests_st201504231710CPPJIT, "StateTests/RandomTests/st201504231710CPPJIT"} + declare_test!{StateTests_RandomTests_st201504231742CPPJIT, "StateTests/RandomTests/st201504231742CPPJIT"} + declare_test!{StateTests_RandomTests_st201504232350CPPJIT, "StateTests/RandomTests/st201504232350CPPJIT"} + declare_test!{StateTests_RandomTests_st201504240140CPPJIT, "StateTests/RandomTests/st201504240140CPPJIT"} + declare_test!{StateTests_RandomTests_st201504240220CPPJIT, "StateTests/RandomTests/st201504240220CPPJIT"} + declare_test!{StateTests_RandomTests_st201504240351CPPJIT, "StateTests/RandomTests/st201504240351CPPJIT"} + declare_test!{StateTests_RandomTests_st201504240817CPPJIT, "StateTests/RandomTests/st201504240817CPPJIT"} + declare_test!{StateTests_RandomTests_st201504241118CPPJIT, "StateTests/RandomTests/st201504241118CPPJIT"} + declare_test!{StateTests_RandomTests_st201505021810CPPJIT, "StateTests/RandomTests/st201505021810CPPJIT"} + declare_test!{StateTests_RandomTests_st201505050557JS, "StateTests/RandomTests/st201505050557JS"} + declare_test!{StateTests_RandomTests_st201505050929GO, "StateTests/RandomTests/st201505050929GO"} + declare_test!{StateTests_RandomTests_st201505050942PYTHON, "StateTests/RandomTests/st201505050942PYTHON"} + declare_test!{StateTests_RandomTests_st201505051004PYTHON, "StateTests/RandomTests/st201505051004PYTHON"} + declare_test!{StateTests_RandomTests_st201505051016PYTHON, "StateTests/RandomTests/st201505051016PYTHON"} + declare_test!{StateTests_RandomTests_st201505051114GO, "StateTests/RandomTests/st201505051114GO"} + declare_test!{StateTests_RandomTests_st201505051238GO, "StateTests/RandomTests/st201505051238GO"} + declare_test!{StateTests_RandomTests_st201505051249GO, "StateTests/RandomTests/st201505051249GO"} + declare_test!{StateTests_RandomTests_st201505051558PYTHON, "StateTests/RandomTests/st201505051558PYTHON"} + declare_test!{StateTests_RandomTests_st201505051611PYTHON, "StateTests/RandomTests/st201505051611PYTHON"} + declare_test!{StateTests_RandomTests_st201505051648JS, "StateTests/RandomTests/st201505051648JS"} + declare_test!{StateTests_RandomTests_st201505051710GO, "StateTests/RandomTests/st201505051710GO"} + declare_test!{StateTests_RandomTests_st201505052013GO, "StateTests/RandomTests/st201505052013GO"} + declare_test!{StateTests_RandomTests_st201505052102JS, "StateTests/RandomTests/st201505052102JS"} + declare_test!{StateTests_RandomTests_st201505052235GO, "StateTests/RandomTests/st201505052235GO"} + declare_test!{StateTests_RandomTests_st201505052238JS, "StateTests/RandomTests/st201505052238JS"} + declare_test!{StateTests_RandomTests_st201505052242PYTHON, "StateTests/RandomTests/st201505052242PYTHON"} + declare_test!{StateTests_RandomTests_st201505052343PYTHON, "StateTests/RandomTests/st201505052343PYTHON"} + declare_test!{StateTests_RandomTests_st201505060120GO, "StateTests/RandomTests/st201505060120GO"} + declare_test!{StateTests_RandomTests_st201505060121GO, "StateTests/RandomTests/st201505060121GO"} + declare_test!{StateTests_RandomTests_st201505060136PYTHON, "StateTests/RandomTests/st201505060136PYTHON"} + declare_test!{StateTests_RandomTests_st201505060646JS, "StateTests/RandomTests/st201505060646JS"} + declare_test!{StateTests_RandomTests_st201505252314CPPJIT, "StateTests/RandomTests/st201505252314CPPJIT"} + declare_test!{StateTests_RandomTests_st201505272131CPPJIT, "StateTests/RandomTests/st201505272131CPPJIT"} + declare_test!{StateTests_RandomTests_st201506040034GO, "StateTests/RandomTests/st201506040034GO"} + declare_test!{StateTests_RandomTests_st201506040157GO, "StateTests/RandomTests/st201506040157GO"} + declare_test!{StateTests_RandomTests_st201506052130GO, "StateTests/RandomTests/st201506052130GO"} + declare_test!{StateTests_RandomTests_st201506060929GO, "StateTests/RandomTests/st201506060929GO"} + declare_test!{StateTests_RandomTests_st201506061255GO, "StateTests/RandomTests/st201506061255GO"} + declare_test!{StateTests_RandomTests_st201506062331GO, "StateTests/RandomTests/st201506062331GO"} + declare_test!{StateTests_RandomTests_st201506070548GO, "StateTests/RandomTests/st201506070548GO"} + declare_test!{StateTests_RandomTests_st201506071050GO, "StateTests/RandomTests/st201506071050GO"} + declare_test!{StateTests_RandomTests_st201506071624GO, "StateTests/RandomTests/st201506071624GO"} + declare_test!{StateTests_RandomTests_st201506071819GO, "StateTests/RandomTests/st201506071819GO"} + declare_test!{StateTests_RandomTests_st201506072007GO, "StateTests/RandomTests/st201506072007GO"} + declare_test!{StateTests_RandomTests_st201506080556GO, "StateTests/RandomTests/st201506080556GO"} + declare_test!{StateTests_RandomTests_st201506080721GO, "StateTests/RandomTests/st201506080721GO"} + declare_test!{StateTests_RandomTests_st201506091836GO, "StateTests/RandomTests/st201506091836GO"} + declare_test!{StateTests_RandomTests_st201506092032GO, "StateTests/RandomTests/st201506092032GO"} + declare_test!{StateTests_RandomTests_st201506101359JS, "StateTests/RandomTests/st201506101359JS"} + declare_test!{StateTests_RandomTests_st201507030359GO, "StateTests/RandomTests/st201507030359GO"} +} diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 787f90262cb..2fab04214cc 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -35,19 +35,20 @@ use db::COL_STATE; pub enum ChainEra { Frontier, Homestead, - DaoHardfork, + Eip150, + TransitionTest, } pub struct TestEngine { engine: Arc, - max_depth: usize + max_depth: usize, } impl TestEngine { pub fn new(max_depth: usize) -> TestEngine { TestEngine { engine: ethereum::new_frontier_test().engine, - max_depth: max_depth + max_depth: max_depth, } } } diff --git a/json/src/spec/engine.rs b/json/src/spec/engine.rs index 3813b1756ef..5c8f887587d 100644 --- a/json/src/spec/engine.rs +++ b/json/src/spec/engine.rs @@ -63,7 +63,7 @@ mod tests { "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit" : "0x", + "homesteadTransition" : "0x", "daoHardforkTransition": "0xffffffffffffffff", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkAccounts": [] diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index d20ab39922e..025ae847501 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -44,8 +44,8 @@ pub struct EthashParams { pub registrar: Option
, /// See main EthashParams docs. - #[serde(rename="frontierCompatibilityModeLimit")] - pub frontier_compatibility_mode_limit: Option, + #[serde(rename="homesteadTransition")] + pub homestead_transition: Option, /// See main EthashParams docs. #[serde(rename="daoHardforkTransition")] @@ -66,6 +66,10 @@ pub struct EthashParams { /// See main EthashParams docs. #[serde(rename="bombDefuseTransition")] pub bomb_defuse_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip150Transition")] + pub eip150_transition: Option, } /// Ethash engine deserialization. @@ -90,7 +94,7 @@ mod tests { "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar": "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0x42", + "homesteadTransition": "0x42", "daoHardforkTransition": "0x08", "daoHardforkBeneficiary": "0xabcabcabcabcabcabcabcabcabcabcabcabcabca", "daoHardforkAccounts": [ @@ -117,7 +121,8 @@ mod tests { ], "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", - "bombDefuseTransition": "0x42" + "bombDefuseTransition": "0x42", + "eip150Transition": "0x42" } }"#; diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 676feff9312..ba81fb48ad9 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -53,7 +53,7 @@ mod tests { #[test] fn params_deserialization() { let s = r#"{ - "frontierCompatibilityModeLimit": "0x118c30", + "homesteadTransition": "0x118c30", "maximumExtraDataSize": "0x20", "networkID" : "0x1", "subprotocolName" : "exp", diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 27c27ce0a04..544407cb8d9 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -66,7 +66,7 @@ mod tests { "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit" : "0x", + "homesteadTransition" : "0x", "daoHardforkTransition": "0xffffffffffffffff", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkAccounts": [] @@ -75,7 +75,7 @@ mod tests { }, "params": { "accountStartNonce": "0x0100000", - "frontierCompatibilityModeLimit": "0x789b0", + "homesteadTransition": "0x789b0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x2", diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 97e4d3bea5c..ff531d57a71 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -208,7 +208,7 @@ const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0xffffffffffffffff", + "homesteadTransition": "0xffffffffffffffff", "daoHardforkTransition": "0xffffffffffffffff", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkAccounts": [] @@ -256,7 +256,7 @@ const POSITIVE_NONCE_SPEC: &'static [u8] = br#"{ "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", - "frontierCompatibilityModeLimit": "0xffffffffffffffff", + "homesteadTransition": "0xffffffffffffffff", "daoHardforkTransition": "0xffffffffffffffff", "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000", "daoHardforkAccounts": [] From 03c1559eadce34e66c4805f240adf018678a9cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 15 Oct 2016 14:44:08 +0200 Subject: [PATCH 11/14] Support for decryption in Signer (#2421) * Adding some tests * Implementing decrypt in queue * Removing code duplication. * Printing public key in ethstore * Bump UI * Normalizing dapps format for signer. * Fixing tests compilation * fix whitespace [ci:skip] --- Cargo.lock | 13 +- ethcore/src/account_provider.rs | 95 ++++++------- ethcore/src/engines/basic_authority.rs | 2 +- ethstore/src/account/safe_account.rs | 7 +- ethstore/src/bin/ethstore.rs | 16 ++- ethstore/src/ethstore.rs | 7 +- ethstore/src/secret_store.rs | 3 +- rpc/src/v1/helpers/dispatch.rs | 78 ++++++----- rpc/src/v1/helpers/errors.rs | 9 ++ rpc/src/v1/helpers/requests.rs | 2 + rpc/src/v1/impls/eth_signing.rs | 151 +++++++++++---------- rpc/src/v1/impls/ethcore.rs | 6 +- rpc/src/v1/impls/personal.rs | 15 +- rpc/src/v1/impls/personal_signer.rs | 12 +- rpc/src/v1/tests/eth.rs | 5 +- rpc/src/v1/tests/mocked/eth.rs | 8 +- rpc/src/v1/tests/mocked/eth_signing.rs | 76 ++++++++++- rpc/src/v1/tests/mocked/ethcore.rs | 23 +++- rpc/src/v1/tests/mocked/personal.rs | 4 +- rpc/src/v1/tests/mocked/personal_signer.rs | 2 +- rpc/src/v1/traits/eth.rs | 44 ------ rpc/src/v1/traits/eth_signing.rs | 63 +++++++++ rpc/src/v1/traits/mod.rs | 5 +- rpc/src/v1/types/confirmations.rs | 18 ++- signer/Cargo.toml | 3 +- signer/src/lib.rs | 2 + signer/src/ws_server/session.rs | 40 ++++-- 27 files changed, 444 insertions(+), 265 deletions(-) create mode 100644 rpc/src/v1/traits/eth_signing.rs diff --git a/Cargo.lock b/Cargo.lock index cee71272771..2cfb39db806 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -505,6 +505,7 @@ dependencies = [ "ethcore-util 1.4.0", "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", "parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1167,7 +1168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-dapps" version = "1.4.0" -source = "git+https://github.com/ethcore/parity-ui.git#926b09b66c4940b09dc82c52adb4afd9e31155bc" +source = "git+https://github.com/ethcore/parity-ui.git#8b1c31319228ad4cf9bd4ae740a0b933aa9e19c7" dependencies = [ "aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1181,7 +1182,7 @@ dependencies = [ [[package]] name = "parity-dapps-home" version = "1.4.0" -source = "git+https://github.com/ethcore/parity-ui.git#926b09b66c4940b09dc82c52adb4afd9e31155bc" +source = "git+https://github.com/ethcore/parity-ui.git#8b1c31319228ad4cf9bd4ae740a0b933aa9e19c7" dependencies = [ "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] @@ -1189,7 +1190,7 @@ dependencies = [ [[package]] name = "parity-dapps-signer" version = "1.4.0" -source = "git+https://github.com/ethcore/parity-ui.git#926b09b66c4940b09dc82c52adb4afd9e31155bc" +source = "git+https://github.com/ethcore/parity-ui.git#8b1c31319228ad4cf9bd4ae740a0b933aa9e19c7" dependencies = [ "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] @@ -1197,7 +1198,7 @@ dependencies = [ [[package]] name = "parity-dapps-status" version = "1.4.0" -source = "git+https://github.com/ethcore/parity-ui.git#926b09b66c4940b09dc82c52adb4afd9e31155bc" +source = "git+https://github.com/ethcore/parity-ui.git#8b1c31319228ad4cf9bd4ae740a0b933aa9e19c7" dependencies = [ "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] @@ -1205,7 +1206,7 @@ dependencies = [ [[package]] name = "parity-dapps-wallet" version = "1.4.0" -source = "git+https://github.com/ethcore/parity-ui.git#926b09b66c4940b09dc82c52adb4afd9e31155bc" +source = "git+https://github.com/ethcore/parity-ui.git#8b1c31319228ad4cf9bd4ae740a0b933aa9e19c7" dependencies = [ "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] @@ -1851,7 +1852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ws" version = "0.5.2" -source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#afbff59776ce16ccec5ee9e218b8891830ee6fdf" +source = "git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable#609b21fdab96c8fffedec8699755ce3bea9454cb" 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/src/account_provider.rs b/ethcore/src/account_provider.rs index 851d015bac1..3f4511f4bab 100644 --- a/ethcore/src/account_provider.rs +++ b/ethcore/src/account_provider.rs @@ -23,7 +23,7 @@ use std::time::{Instant, Duration}; use util::{Mutex, RwLock}; use ethstore::{SecretStore, Error as SSError, SafeAccount, EthStore}; use ethstore::dir::{KeyDirectory}; -use ethstore::ethkey::{Address, Message, Secret, Random, Generator}; +use ethstore::ethkey::{Address, Message, Public, Secret, Random, Generator}; use ethjson::misc::AccountMeta; pub use ethstore::ethkey::Signature; @@ -182,9 +182,16 @@ impl AccountProvider { /// Creates new random account. pub fn new_account(&self, password: &str) -> Result { - let secret = Random.generate().unwrap().secret().clone(); + self.new_account_and_public(password).map(|d| d.0) + } + + /// Creates new random account and returns address and public key + pub fn new_account_and_public(&self, password: &str) -> Result<(Address, Public), Error> { + let acc = Random.generate().unwrap(); + let public = acc.public().clone(); + let secret = acc.secret().clone(); let address = try!(self.sstore.insert_account(secret, password)); - Ok(address) + Ok((address, public)) } /// Inserts new account into underlying store. @@ -280,6 +287,21 @@ impl AccountProvider { Ok(()) } + fn password(&self, account: &Address) -> Result { + let mut unlocked = self.unlocked.lock(); + let data = try!(unlocked.get(account).ok_or(Error::NotUnlocked)).clone(); + if let Unlock::Temp = data.unlock { + unlocked.remove(account).expect("data exists: so key must exist: qed"); + } + if let Unlock::Timed((ref start, ref duration)) = data.unlock { + if start.elapsed() > Duration::from_millis(*duration as u64) { + unlocked.remove(account).expect("data exists: so key must exist: qed"); + return Err(Error::NotUnlocked); + } + } + Ok(data.password.clone()) + } + /// Unlocks account permanently. pub fn unlock_account_permanently(&self, account: Address, password: String) -> Result<(), Error> { self.unlock_account(account, password, Unlock::Perm) @@ -301,51 +323,16 @@ impl AccountProvider { unlocked.get(&account).is_some() } - /// Signs the message. Account must be unlocked. - pub fn sign(&self, account: Address, message: Message) -> Result { - let data = { - let mut unlocked = self.unlocked.lock(); - let data = try!(unlocked.get(&account).ok_or(Error::NotUnlocked)).clone(); - if let Unlock::Temp = data.unlock { - unlocked.remove(&account).expect("data exists: so key must exist: qed"); - } - if let Unlock::Timed((ref start, ref duration)) = data.unlock { - if start.elapsed() > Duration::from_millis(*duration as u64) { - unlocked.remove(&account).expect("data exists: so key must exist: qed"); - return Err(Error::NotUnlocked); - } - } - data - }; - - let signature = try!(self.sstore.sign(&account, &data.password, &message)); - Ok(signature) - } - - /// Decrypts a message. Account must be unlocked. - pub fn decrypt(&self, account: Address, shared_mac: &[u8], message: &[u8]) -> Result, Error> { - let data = { - let mut unlocked = self.unlocked.lock(); - let data = try!(unlocked.get(&account).ok_or(Error::NotUnlocked)).clone(); - if let Unlock::Temp = data.unlock { - unlocked.remove(&account).expect("data exists: so key must exist: qed"); - } - if let Unlock::Timed((ref start, ref duration)) = data.unlock { - if start.elapsed() > Duration::from_millis(*duration as u64) { - unlocked.remove(&account).expect("data exists: so key must exist: qed"); - return Err(Error::NotUnlocked); - } - } - data - }; - - Ok(try!(self.sstore.decrypt(&account, &data.password, shared_mac, message))) + /// Signs the message. If password is not provided the account must be unlocked. + pub fn sign(&self, account: Address, password: Option, message: Message) -> Result { + let password = try!(password.map(Ok).unwrap_or_else(|| self.password(&account))); + Ok(try!(self.sstore.sign(&account, &password, &message))) } - /// Unlocks an account, signs the message, and locks it again. - pub fn sign_with_password(&self, account: Address, password: String, message: Message) -> Result { - let signature = try!(self.sstore.sign(&account, &password, &message)); - Ok(signature) + /// Decrypts a message. If password is not provided the account must be unlocked. + pub fn decrypt(&self, account: Address, password: Option, shared_mac: &[u8], message: &[u8]) -> Result, Error> { + let password = try!(password.map(Ok).unwrap_or_else(|| self.password(&account))); + Ok(try!(self.sstore.decrypt(&account, &password, shared_mac, message))) } /// Returns the underlying `SecretStore` reference if one exists. @@ -386,8 +373,8 @@ mod tests { assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); assert!(ap.unlock_account_temporarily(kp.address(), "test1".into()).is_err()); assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_err()); + assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); + assert!(ap.sign(kp.address(), None, Default::default()).is_err()); } #[test] @@ -397,11 +384,11 @@ mod tests { assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); assert!(ap.unlock_account_permanently(kp.address(), "test1".into()).is_err()); assert!(ap.unlock_account_permanently(kp.address(), "test".into()).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_ok()); + assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); + assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); assert!(ap.unlock_account_temporarily(kp.address(), "test".into()).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_ok()); + assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); + assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); } #[test] @@ -411,8 +398,8 @@ mod tests { assert!(ap.insert_account(kp.secret().clone(), "test").is_ok()); assert!(ap.unlock_account_timed(kp.address(), "test1".into(), 2000).is_err()); assert!(ap.unlock_account_timed(kp.address(), "test".into(), 2000).is_ok()); - assert!(ap.sign(kp.address(), Default::default()).is_ok()); + assert!(ap.sign(kp.address(), None, Default::default()).is_ok()); ::std::thread::sleep(Duration::from_millis(2000)); - assert!(ap.sign(kp.address(), Default::default()).is_err()); + assert!(ap.sign(kp.address(), None, Default::default()).is_err()); } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 6e3c2f1dd99..bd3eb5bc693 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -112,7 +112,7 @@ impl Engine for BasicAuthority { let header = block.header(); let message = header.bare_hash(); // account should be pernamently unlocked, otherwise sealing will fail - if let Ok(signature) = ap.sign(*block.header().author(), message) { + if let Ok(signature) = ap.sign(*block.header().author(), None, message) { return Some(vec![::rlp::encode(&(&*signature as &[u8])).to_vec()]); } else { trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable"); diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 315fd283b58..5dab3525135 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::{KeyPair, sign, Address, Secret, Signature, Message}; +use ethkey::{KeyPair, sign, Address, Secret, Signature, Message, Public}; use {json, Error, crypto}; use crypto::Keccak256; use random::Random; @@ -180,6 +180,11 @@ impl SafeAccount { crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) } + pub fn public(&self, password: &str) -> Result { + let secret = try!(self.crypto.secret(password)); + Ok(try!(KeyPair::from_secret(secret)).public().clone()) + } + pub fn change_password(&self, old_password: &str, new_password: &str, iterations: u32) -> Result { let secret = try!(self.crypto.secret(old_password)); let result = SafeAccount { diff --git a/ethstore/src/bin/ethstore.rs b/ethstore/src/bin/ethstore.rs index 94823dc061f..9d499723b3f 100644 --- a/ethstore/src/bin/ethstore.rs +++ b/ethstore/src/bin/ethstore.rs @@ -37,6 +37,7 @@ Usage: ethstore import-wallet [--dir DIR] ethstore remove
[--dir DIR] ethstore sign
[--dir DIR] + ethstore public
ethstore [-h | --help] Options: @@ -56,6 +57,7 @@ Commands: import-wallet Import presale wallet. remove Remove account. sign Sign message. + public Displays public key for an address. "#; #[derive(Debug, RustcDecodable)] @@ -67,6 +69,7 @@ struct Args { cmd_import_wallet: bool, cmd_remove: bool, cmd_sign: bool, + cmd_public: bool, arg_secret: String, arg_password: String, arg_old_pwd: String, @@ -103,7 +106,7 @@ fn key_dir(location: &str) -> Result, Error> { fn format_accounts(accounts: &[Address]) -> String { accounts.iter() .enumerate() - .map(|(i, a)| format!("{:2}: {}", i, a)) + .map(|(i, a)| format!("{:2}: 0x{:?}", i, a)) .collect::>() .join("\n") } @@ -128,7 +131,7 @@ fn execute(command: I) -> Result where I: IntoIterator(command: I) -> Result where I: IntoIterator(command: I) -> Result where I: IntoIterator Result { + let account = try!(self.get(account)); + account.public(password) + } + fn uuid(&self, address: &Address) -> Result { let account = try!(self.get(address)); Ok(account.id.into()) diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index aa79cb8b678..06f38922b3d 100644 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::{Address, Message, Signature, Secret}; +use ethkey::{Address, Message, Signature, Secret, Public}; use Error; use json::UUID; @@ -27,6 +27,7 @@ pub trait SecretStore: Send + Sync { fn sign(&self, account: &Address, password: &str, message: &Message) -> Result; fn decrypt(&self, account: &Address, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error>; + fn public(&self, account: &Address, password: &str) -> Result; fn accounts(&self) -> Result, Error>; fn uuid(&self, account: &Address) -> Result; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index df2d8cbd3e2..56124108a5b 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -14,58 +14,60 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::{Address, H256, U256, Uint}; +use util::{Address, H256, U256, Uint, Bytes}; use util::bytes::ToPretty; +use ethkey::Signature; use ethcore::miner::MinerService; use ethcore::client::MiningBlockChainClient; use ethcore::transaction::{Action, SignedTransaction, Transaction}; use ethcore::account_provider::AccountProvider; use jsonrpc_core::{Error, Value, to_value}; use v1::helpers::TransactionRequest; -use v1::types::{H256 as RpcH256, H520 as RpcH520}; +use v1::types::{H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes}; use v1::helpers::errors; -fn prepare_transaction(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService { - Transaction { - nonce: request.nonce - .or_else(|| miner - .last_nonce(&request.from) - .map(|nonce| nonce + U256::one())) - .unwrap_or_else(|| client.latest_nonce(&request.from)), - - action: request.to.map_or(Action::Create, Action::Call), - gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()), - gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)), - value: request.value.unwrap_or_else(U256::zero), - data: request.data.map_or_else(Vec::new, |b| b.to_vec()), - } -} +pub const DEFAULT_MAC: [u8; 2] = [0, 0]; pub fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result where C: MiningBlockChainClient, M: MinerService { let hash = RpcH256::from(signed_transaction.hash()); - let import = miner.import_own_transaction(client, signed_transaction); - - import + miner.import_own_transaction(client, signed_transaction) .map_err(errors::from_transaction_error) .map(|_| hash) } -pub fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result { - accounts.sign_with_password(address, pass, hash) - .map_err(errors::from_password_error) - .map(|hash| to_value(&RpcH520::from(hash))) +fn signature(accounts: &AccountProvider, address: Address, password: Option, hash: H256) -> Result { + accounts.sign(address, password.clone(), hash).map_err(|e| match password { + Some(_) => errors::from_password_error(e), + None => errors::from_signing_error(e), + }) } -pub fn unlock_sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result +pub fn sign(accounts: &AccountProvider, address: Address, password: Option, hash: H256) -> Result { + signature(accounts, address, password, hash) + .map(RpcH520::from) + .map(to_value) +} + +pub fn decrypt(accounts: &AccountProvider, address: Address, password: Option, msg: Bytes) -> Result { + accounts.decrypt(address, password.clone(), &DEFAULT_MAC, &msg) + .map_err(|e| match password { + Some(_) => errors::from_password_error(e), + None => errors::from_signing_error(e), + }) + .map(RpcBytes::from) + .map(to_value) +} + +pub fn sign_and_dispatch(client: &C, miner: &M, accounts: &AccountProvider, request: TransactionRequest, password: Option) -> Result where C: MiningBlockChainClient, M: MinerService { let address = request.from; let signed_transaction = { let t = prepare_transaction(client, miner, request); let hash = t.hash(); - let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(errors::from_password_error)); + let signature = try!(signature(accounts, address, password, hash)); t.with_signature(signature) }; @@ -73,18 +75,20 @@ pub fn unlock_sign_and_dispatch(client: &C, miner: &M, request: Transactio dispatch_transaction(&*client, &*miner, signed_transaction).map(to_value) } -pub fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result - where C: MiningBlockChainClient, M: MinerService { - - let signed_transaction = { - let t = prepare_transaction(client, miner, request); - let hash = t.hash(); - let signature = try!(account_provider.sign(address, hash).map_err(errors::from_signing_error)); - t.with_signature(signature) - }; +fn prepare_transaction(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService { + Transaction { + nonce: request.nonce + .or_else(|| miner + .last_nonce(&request.from) + .map(|nonce| nonce + U256::one())) + .unwrap_or_else(|| client.latest_nonce(&request.from)), - trace!(target: "miner", "send_transaction: dispatching tx: {}", ::rlp::encode(&signed_transaction).to_vec().pretty()); - dispatch_transaction(&*client, &*miner, signed_transaction).map(to_value) + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()), + gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |b| b.to_vec()), + } } pub fn default_gas_price(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService { diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 0d7902897af..c54cd9c34d8 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -43,6 +43,7 @@ mod codes { pub const REQUEST_REJECTED_LIMIT: i64 = -32041; pub const REQUEST_NOT_FOUND: i64 = -32042; pub const COMPILATION_ERROR: i64 = -32050; + pub const ENCRYPTION_ERROR: i64 = -32055; pub const FETCH_ERROR: i64 = -32060; } @@ -166,6 +167,14 @@ pub fn signer_disabled() -> Error { } } +pub fn encryption_error(error: T) -> Error { + Error { + code: ErrorCode::ServerError(codes::ENCRYPTION_ERROR), + message: "Encryption error.".into(), + data: Some(Value::String(format!("{:?}", error))), + } +} + pub fn from_fetch_error(error: FetchError) -> Error { Error { code: ErrorCode::ServerError(codes::FETCH_ERROR), diff --git a/rpc/src/v1/helpers/requests.rs b/rpc/src/v1/helpers/requests.rs index 6a30d80bb7e..5cb6108c1df 100644 --- a/rpc/src/v1/helpers/requests.rs +++ b/rpc/src/v1/helpers/requests.rs @@ -103,4 +103,6 @@ pub enum ConfirmationPayload { Transaction(FilledTransactionRequest), /// Sign request Sign(Address, H256), + /// Decrypt request + Decrypt(Address, Bytes), } diff --git a/rpc/src/v1/impls/eth_signing.rs b/rpc/src/v1/impls/eth_signing.rs index 9290a942512..e8b81d0c867 100644 --- a/rpc/src/v1/impls/eth_signing.rs +++ b/rpc/src/v1/impls/eth_signing.rs @@ -24,9 +24,9 @@ use util::{U256, Address, H256, Mutex}; use transient_hashmap::TransientHashMap; use ethcore::account_provider::AccountProvider; use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest, SignerService}; -use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch}; +use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch, sign, decrypt}; use v1::traits::EthSigning; -use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256, Bytes as RpcBytes}; +use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, U256 as RpcU256, Bytes as RpcBytes}; fn fill_optional_fields(request: TRequest, client: &C, miner: &M) -> FilledRequest where C: MiningBlockChainClient, M: MinerService { @@ -76,41 +76,59 @@ impl EthSigningQueueClient where C: MiningBlockChainClient, M: Miner Ok(()) } + fn add_to_queue(&self, sender: Address, when_unlocked: WhenUnlocked, payload: Payload) + -> Result where + WhenUnlocked: Fn(&AccountProvider) -> Result, + Payload: Fn() -> ConfirmationPayload, { + + let accounts = take_weak!(self.accounts); + if accounts.is_unlocked(sender) { + return when_unlocked(&accounts).map(DispatchResult::Value); + } + + take_weak!(self.signer).add_request(payload()) + .map(DispatchResult::Promise) + .map_err(|_| errors::request_rejected_limit()) + } + + fn handle_dispatch(&self, res: Result, ready: Ready) { + match res { + Ok(DispatchResult::Value(v)) => ready.ready(Ok(v)), + Ok(DispatchResult::Promise(promise)) => { + promise.wait_for_result(move |result| { + ready.ready(result.unwrap_or_else(|| Err(errors::request_rejected()))) + }) + }, + Err(e) => ready.ready(Err(e)), + } + } + fn dispatch_sign(&self, params: Params) -> Result { from_params::<(RpcH160, RpcH256)>(params).and_then(|(address, msg)| { let address: Address = address.into(); let msg: H256 = msg.into(); - let accounts = take_weak!(self.accounts); - if accounts.is_unlocked(address) { - return Ok(DispatchResult::Value(to_value(&accounts.sign(address, msg).ok().map_or_else(RpcH520::default, Into::into)))) - } - - let signer = take_weak!(self.signer); - signer.add_request(ConfirmationPayload::Sign(address, msg)) - .map(DispatchResult::Promise) - .map_err(|_| errors::request_rejected_limit()) + self.add_to_queue( + address, + |accounts| sign(accounts, address, None, msg.clone()), + || ConfirmationPayload::Sign(address, msg.clone()), + ) }) } fn dispatch_transaction(&self, params: Params) -> Result { - from_params::<(TransactionRequest, )>(params) - .and_then(|(request, )| { - let request: TRequest = request.into(); - let accounts = take_weak!(self.accounts); - let (client, miner) = (take_weak!(self.client), take_weak!(self.miner)); - - if accounts.is_unlocked(request.from) { - let sender = request.from; - return sign_and_dispatch(&*client, &*miner, request, &*accounts, sender).map(DispatchResult::Value); + from_params::<(TransactionRequest, )>(params).and_then(|(request, )| { + let request: TRequest = request.into(); + let (client, miner) = (take_weak!(self.client), take_weak!(self.miner)); + self.add_to_queue( + request.from, + |accounts| sign_and_dispatch(&*client, &*miner, accounts, request.clone(), None), + || { + let request = fill_optional_fields(request.clone(), &*client, &*miner); + ConfirmationPayload::Transaction(request) } - - let signer = take_weak!(self.signer); - let request = fill_optional_fields(request, &*client, &*miner); - signer.add_request(ConfirmationPayload::Transaction(request)) - .map(DispatchResult::Promise) - .map_err(|_| errors::request_rejected_limit()) - }) + ) + }) } } @@ -118,19 +136,6 @@ impl EthSigning for EthSigningQueueClient where C: MiningBlockChainClient + 'static, M: MinerService + 'static { - fn sign(&self, params: Params, ready: Ready) { - let res = self.active().and_then(|_| self.dispatch_sign(params)); - match res { - Ok(DispatchResult::Promise(promise)) => { - promise.wait_for_result(move |result| { - ready.ready(result.unwrap_or_else(|| Err(errors::request_rejected()))) - }) - }, - Ok(DispatchResult::Value(v)) => ready.ready(Ok(v)), - Err(e) => ready.ready(Err(e)), - } - } - fn post_sign(&self, params: Params) -> Result { try!(self.active()); self.dispatch_sign(params).map(|result| match result { @@ -143,19 +148,6 @@ impl EthSigning for EthSigningQueueClient }) } - fn send_transaction(&self, params: Params, ready: Ready) { - let res = self.active().and_then(|_| self.dispatch_transaction(params)); - match res { - Ok(DispatchResult::Promise(promise)) => { - promise.wait_for_result(move |result| { - ready.ready(result.unwrap_or_else(|| Err(errors::request_rejected()))) - }) - }, - Ok(DispatchResult::Value(v)) => ready.ready(Ok(v)), - Err(e) => ready.ready(Err(e)), - } - } - fn post_transaction(&self, params: Params) -> Result { try!(self.active()); self.dispatch_transaction(params).map(|result| match result { @@ -168,13 +160,6 @@ impl EthSigning for EthSigningQueueClient }) } - fn decrypt_message(&self, params: Params) -> Result { - try!(self.active()); - from_params::<(RpcH160, RpcBytes)>(params).and_then(|(_account, _ciphertext)| { - Err(errors::unimplemented()) - }) - } - fn check_request(&self, params: Params) -> Result { try!(self.active()); let mut pending = self.pending.lock(); @@ -192,6 +177,32 @@ impl EthSigning for EthSigningQueueClient res }) } + + fn sign(&self, params: Params, ready: Ready) { + let res = self.active().and_then(|_| self.dispatch_sign(params)); + self.handle_dispatch(res, ready); + } + + fn send_transaction(&self, params: Params, ready: Ready) { + let res = self.active().and_then(|_| self.dispatch_transaction(params)); + self.handle_dispatch(res, ready); + } + + fn decrypt_message(&self, params: Params, ready: Ready) { + let res = self.active() + .and_then(|_| from_params::<(RpcH160, RpcBytes)>(params)) + .and_then(|(address, msg)| { + let address: Address = address.into(); + + self.add_to_queue( + address, + |accounts| decrypt(accounts, address, None, msg.clone().into()), + || ConfirmationPayload::Decrypt(address, msg.clone().into()) + ) + }); + + self.handle_dispatch(res, ready); + } } /// Implementation of functions that require signing when no trusted signer is used. @@ -232,9 +243,7 @@ impl EthSigning for EthSigningUnsafeClient where ready.ready(self.active() .and_then(|_| from_params::<(RpcH160, RpcH256)>(params)) .and_then(|(address, msg)| { - let address: Address = address.into(); - let msg: H256 = msg.into(); - Ok(to_value(&take_weak!(self.accounts).sign(address, msg).ok().map_or_else(RpcH520::default, Into::into))) + sign(&*take_weak!(self.accounts), address.into(), None, msg.into()) })) } @@ -242,18 +251,16 @@ impl EthSigning for EthSigningUnsafeClient where ready.ready(self.active() .and_then(|_| from_params::<(TransactionRequest, )>(params)) .and_then(|(request, )| { - let request: TRequest = request.into(); - let sender = request.from; - sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, &*take_weak!(self.accounts), sender) + sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), &*take_weak!(self.accounts), request.into(), None) })) } - fn decrypt_message(&self, params: Params) -> Result { - try!(self.active()); - from_params::<(RpcH160, RpcBytes)>(params).and_then(|(address, ciphertext)| { - let s = try!(take_weak!(self.accounts).decrypt(address.into(), &[0; 0], &ciphertext.0).map_err(|_| Error::internal_error())); - Ok(to_value(RpcBytes::from(s))) - }) + fn decrypt_message(&self, params: Params, ready: Ready) { + ready.ready(self.active() + .and_then(|_| from_params::<(RpcH160, RpcBytes)>(params)) + .and_then(|(address, ciphertext)| { + decrypt(&*take_weak!(self.accounts), address.into(), None, ciphertext.0) + })) } fn post_sign(&self, _: Params) -> Result { diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index 3b756342d2f..33123ddd5d9 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -35,6 +35,8 @@ use jsonrpc_core::Error; use v1::traits::Ethcore; use v1::types::{Bytes, U256, H160, H256, H512, Peers, Transaction, RpcSettings}; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; +use v1::helpers::dispatch::DEFAULT_MAC; +use v1::helpers::params::expect_no_params; use v1::helpers::auto_args::Ready; /// Ethcore implementation. @@ -265,8 +267,8 @@ impl Ethcore for EthcoreClient where fn encrypt_message(&self, key: H512, phrase: Bytes) -> Result { try!(self.active()); - ecies::encrypt(&key.into(), &[0; 0], &phrase.0) - .map_err(|_| Error::internal_error()) + ecies::encrypt(&key.into(), &DEFAULT_MAC, &phrase.0) + .map_err(errors::encryption_error) .map(Into::into) } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 009f173b322..0830effd5b0 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -22,9 +22,9 @@ use jsonrpc_core::*; use ethkey::{Brain, Generator}; use v1::traits::Personal; use v1::types::{H160 as RpcH160, TransactionRequest}; -use v1::helpers::{errors, TransactionRequest as TRequest}; +use v1::helpers::errors; use v1::helpers::params::expect_no_params; -use v1::helpers::dispatch::unlock_sign_and_dispatch; +use v1::helpers::dispatch::sign_and_dispatch; use ethcore::account_provider::AccountProvider; use ethcore::client::MiningBlockChainClient; use ethcore::miner::MinerService; @@ -139,10 +139,13 @@ impl Personal for PersonalClient where C: MiningBl try!(self.active()); from_params::<(TransactionRequest, String)>(params) .and_then(|(request, password)| { - let request: TRequest = request.into(); - let accounts = take_weak!(self.accounts); - - unlock_sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, &*accounts, password) + sign_and_dispatch( + &*take_weak!(self.client), + &*take_weak!(self.miner), + &*take_weak!(self.accounts), + request.into(), + Some(password) + ) }) } diff --git a/rpc/src/v1/impls/personal_signer.rs b/rpc/src/v1/impls/personal_signer.rs index 441ed679bbb..b3a93736a2b 100644 --- a/rpc/src/v1/impls/personal_signer.rs +++ b/rpc/src/v1/impls/personal_signer.rs @@ -25,7 +25,7 @@ use v1::traits::PersonalSigner; use v1::types::{TransactionModification, ConfirmationRequest, U256}; use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload}; use v1::helpers::params::expect_no_params; -use v1::helpers::dispatch::{unlock_sign_and_dispatch, signature_with_password}; +use v1::helpers::dispatch::{sign_and_dispatch, sign, decrypt}; /// Transactions confirmation (personal) rpc implementation. pub struct SignerClient where C: MiningBlockChainClient, M: MinerService { @@ -87,12 +87,14 @@ impl PersonalSigner for SignerClient where C: Mini if let Some(gas_price) = modification.gas_price { request.gas_price = gas_price.into(); } - - unlock_sign_and_dispatch(&*client, &*miner, request.into(), &*accounts, pass) + sign_and_dispatch(&*client, &*miner, &*accounts, request.into(), Some(pass)) }, ConfirmationPayload::Sign(address, hash) => { - signature_with_password(&*accounts, address, hash, pass) - } + sign(&*accounts, address, Some(pass), hash) + }, + ConfirmationPayload::Decrypt(address, msg) => { + decrypt(&*accounts, address, Some(pass), msg) + }, }; if let Ok(ref response) = result { signer.request_confirmed(id, Ok(response.clone())); diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index ff531d57a71..1dfe9796858 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -33,9 +33,10 @@ use util::{U256, H256, Uint, Address}; use jsonrpc_core::IoHandler; use ethjson::blockchain::BlockChain; -use v1::types::U256 as NU256; -use v1::traits::eth::{Eth, EthSigning}; use v1::impls::{EthClient, EthSigningUnsafeClient}; +use v1::types::U256 as NU256; +use v1::traits::eth::Eth; +use v1::traits::eth_signing::EthSigning; use v1::tests::helpers::{TestSyncProvider, Config}; fn account_provider() -> Arc { diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index eb3fbaf6e74..e41ca323109 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -264,7 +264,7 @@ fn rpc_eth_sign() { let account = tester.accounts_provider.new_account("abcd").unwrap(); tester.accounts_provider.unlock_account_permanently(account, "abcd".into()).unwrap(); let message = H256::from("0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f"); - let signed = tester.accounts_provider.sign(account, message).unwrap(); + let signed = tester.accounts_provider.sign(account, None, message).unwrap(); let req = r#"{ "jsonrpc": "2.0", @@ -709,7 +709,7 @@ fn rpc_eth_send_transaction() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts_provider.sign(address, t.hash()).unwrap(); + let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap(); let t = t.with_signature(signature); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; @@ -726,7 +726,7 @@ fn rpc_eth_send_transaction() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts_provider.sign(address, t.hash()).unwrap(); + let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap(); let t = t.with_signature(signature); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; @@ -791,7 +791,7 @@ fn rpc_eth_send_raw_transaction() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts_provider.sign(address, t.hash()).unwrap(); + let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap(); let t = t.with_signature(signature); let rlp = ::rlp::encode(&t).to_vec().to_hex(); diff --git a/rpc/src/v1/tests/mocked/eth_signing.rs b/rpc/src/v1/tests/mocked/eth_signing.rs index 1bf901e5f88..fc5800cd717 100644 --- a/rpc/src/v1/tests/mocked/eth_signing.rs +++ b/rpc/src/v1/tests/mocked/eth_signing.rs @@ -16,16 +16,20 @@ use std::str::FromStr; use std::sync::Arc; -use jsonrpc_core::{IoHandler, to_value}; +use jsonrpc_core::{IoHandler, to_value, Success}; use v1::impls::EthSigningQueueClient; -use v1::traits::EthSigning; +use v1::traits::{EthSigning, Ethcore}; use v1::helpers::{SignerService, SigningQueue}; -use v1::types::{H256 as RpcH256, H520 as RpcH520}; +use v1::types::{H256 as RpcH256, H520 as RpcH520, Bytes}; use v1::tests::helpers::TestMinerService; +use v1::tests::mocked::ethcore; + use util::{Address, FixedHash, Uint, U256, H256, H520}; use ethcore::account_provider::AccountProvider; use ethcore::client::TestBlockChainClient; use ethcore::transaction::{Transaction, Action}; +use ethstore::ethkey::{Generator, Random}; +use serde_json; struct EthSigningTester { pub signer: Arc, @@ -178,7 +182,7 @@ fn should_sign_if_account_is_unlocked() { let acc = tester.accounts.new_account("test").unwrap(); tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap(); - let signature = tester.accounts.sign(acc, hash).unwrap(); + let signature = tester.accounts.sign(acc, None, hash).unwrap(); // when let request = r#"{ @@ -242,7 +246,7 @@ fn should_dispatch_transaction_if_account_is_unlock() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts.sign(acc, t.hash()).unwrap(); + let signature = tester.accounts.sign(acc, None, t.hash()).unwrap(); let t = t.with_signature(signature); // when @@ -263,3 +267,65 @@ fn should_dispatch_transaction_if_account_is_unlock() { // then assert_eq!(tester.io.handle_request_sync(&request), Some(response.to_owned())); } + +#[test] +fn should_decrypt_message_if_account_is_unlocked() { + // given + let tester = eth_signing(); + let sync = ethcore::sync_provider(); + let net = ethcore::network_service(); + let ethcore_client = ethcore::ethcore_client(&tester.client, &tester.miner, &sync, &net); + tester.io.add_delegate(ethcore_client.to_delegate()); + let (address, public) = tester.accounts.new_account_and_public("test").unwrap(); + tester.accounts.unlock_account_permanently(address, "test".into()).unwrap(); + + + // First encrypt message + let request = format!("{}0x{:?}{}", + r#"{"jsonrpc": "2.0", "method": "ethcore_encryptMessage", "params":[""#, + public, + r#"", "0x01020304"], "id": 1}"# + ); + let encrypted: Success = serde_json::from_str(&tester.io.handle_request_sync(&request).unwrap()).unwrap(); + + // then call decrypt + let request = format!("{}{:?}{}{:?}{}", + r#"{"jsonrpc": "2.0", "method": "ethcore_decryptMessage", "params":["0x"#, + address, + r#"","#, + encrypted.result, + r#"], "id": 1}"# + ); + println!("Request: {:?}", request); + let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#; + + // then + assert_eq!(tester.io.handle_request_sync(&request), Some(response.into())); +} + +#[test] +fn should_add_decryption_to_the_queue() { + // given + let tester = eth_signing(); + let acc = Random.generate().unwrap(); + assert_eq!(tester.signer.requests().len(), 0); + + // when + let request = r#"{ + "jsonrpc": "2.0", + "method": "ethcore_decryptMessage", + "params": ["0x"#.to_owned() + &format!("{:?}", acc.address()) + r#"", + "0x012345"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0102","id":1}"#; + + // then + let async_result = tester.io.handle_request(&request).unwrap(); + assert_eq!(tester.signer.requests().len(), 1); + // respond + tester.signer.request_confirmed(U256::from(1), Ok(to_value(Bytes(vec![0x1, 0x2])))); + assert!(async_result.on_result(move |res| { + assert_eq!(res, response.to_owned()); + })); +} diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index f09d84d5bf6..4cf23d46e2c 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -19,6 +19,7 @@ use util::log::RotatingLogger; use util::U256; use ethsync::ManageNetwork; use ethcore::client::{TestBlockChainClient}; +use ethstore::ethkey::{Generator, Random}; use jsonrpc_core::IoHandler; use v1::{Ethcore, EthcoreClient}; @@ -34,7 +35,7 @@ fn client_service() -> Arc { Arc::new(TestBlockChainClient::default()) } -fn sync_provider() -> Arc { +pub fn sync_provider() -> Arc { Arc::new(TestSyncProvider::new(Config { network_id: U256::from(3), num_peers: 120, @@ -56,13 +57,13 @@ fn settings() -> Arc { }) } -fn network_service() -> Arc { +pub fn network_service() -> Arc { Arc::new(TestManageNetwork) } -type TestEthcoreClient = EthcoreClient; +pub type TestEthcoreClient = EthcoreClient; -fn ethcore_client( +pub fn ethcore_client( client: &Arc, miner: &Arc, sync: &Arc, @@ -324,3 +325,17 @@ fn rpc_ethcore_pending_transactions() { assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } + +#[test] +fn rpc_ethcore_encrypt() { + let miner = miner_service(); + let client = client_service(); + let sync = sync_provider(); + let net = network_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); + let key = format!("{:?}", Random.generate().unwrap().public()); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_encryptMessage", "params":["0x"#.to_owned() + &key + r#"", "0x01"], "id": 1}"#; + assert!(io.handle_request_sync(&request).unwrap().contains("result"), "Should return success."); +} diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index aa4bf29c119..c3c3d2954cd 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -227,7 +227,7 @@ fn sign_and_send_transaction() { data: vec![] }; tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap(); - let signature = tester.accounts.sign(address, t.hash()).unwrap(); + let signature = tester.accounts.sign(address, None, t.hash()).unwrap(); let t = t.with_signature(signature); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; @@ -245,7 +245,7 @@ fn sign_and_send_transaction() { data: vec![] }; tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap(); - let signature = tester.accounts.sign(address, t.hash()).unwrap(); + let signature = tester.accounts.sign(address, None, t.hash()).unwrap(); let t = t.with_signature(signature); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; diff --git a/rpc/src/v1/tests/mocked/personal_signer.rs b/rpc/src/v1/tests/mocked/personal_signer.rs index 04ae829ee62..650f1655303 100644 --- a/rpc/src/v1/tests/mocked/personal_signer.rs +++ b/rpc/src/v1/tests/mocked/personal_signer.rs @@ -186,7 +186,7 @@ fn should_confirm_transaction_and_dispatch() { data: vec![] }; tester.accounts.unlock_account_temporarily(address, "test".into()).unwrap(); - let signature = tester.accounts.sign(address, t.hash()).unwrap(); + let signature = tester.accounts.sign(address, None, t.hash()).unwrap(); let t = t.with_signature(signature); assert_eq!(tester.signer.requests().len(), 1); diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 62301e21fb5..7d9aa47f3ec 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . //! Eth rpc interface. -use std::sync::Arc; use jsonrpc_core::*; use v1::types::{Block, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index}; @@ -198,46 +197,3 @@ build_rpc_trait! { fn uninstall_filter(&self, Index) -> Result; } } - -/// Signing methods implementation relying on unlocked accounts. -pub trait EthSigning: Sized + Send + Sync + 'static { - /// Signs the data with given address signature. - fn sign(&self, _: Params, _: Ready); - - /// Posts sign request asynchronously. - /// Will return a confirmation ID for later use with check_transaction. - fn post_sign(&self, _: Params) -> Result; - - /// Sends transaction; will block for 20s to try to return the - /// transaction hash. - /// If it cannot yet be signed, it will return a transaction ID for - /// later use with check_transaction. - fn send_transaction(&self, _: Params, _: Ready); - - /// Posts transaction asynchronously. - /// Will return a transaction ID for later use with check_transaction. - fn post_transaction(&self, _: Params) -> Result; - - /// Checks the progress of a previously posted request (transaction/sign). - /// Should be given a valid send_transaction ID. - /// Returns the transaction hash, the zero hash (not yet available), - /// or the signature, - /// or an error. - fn check_request(&self, _: Params) -> Result; - - /// Decrypt some ECIES-encrypted message. - /// First parameter is the address with which it is encrypted, second is the ciphertext. - fn decrypt_message(&self, _: Params) -> Result; - - /// Should be used to convert object to io delegate. - fn to_delegate(self) -> IoDelegate { - let mut delegate = IoDelegate::new(Arc::new(self)); - delegate.add_async_method("eth_sign", EthSigning::sign); - delegate.add_async_method("eth_sendTransaction", EthSigning::send_transaction); - delegate.add_method("eth_postSign", EthSigning::post_sign); - delegate.add_method("eth_postTransaction", EthSigning::post_transaction); - delegate.add_method("eth_checkRequest", EthSigning::check_request); - delegate.add_method("ethcore_decryptMessage", EthSigning::decrypt_message); - delegate - } -} diff --git a/rpc/src/v1/traits/eth_signing.rs b/rpc/src/v1/traits/eth_signing.rs new file mode 100644 index 00000000000..1d6f6e5019d --- /dev/null +++ b/rpc/src/v1/traits/eth_signing.rs @@ -0,0 +1,63 @@ +// 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 . + +//! Eth rpc interface. +use std::sync::Arc; +use jsonrpc_core::*; + +/// Signing methods implementation relying on unlocked accounts. +pub trait EthSigning: Sized + Send + Sync + 'static { + /// Signs the data with given address signature. + fn sign(&self, _: Params, _: Ready); + + /// Posts sign request asynchronously. + /// Will return a confirmation ID for later use with check_transaction. + fn post_sign(&self, _: Params) -> Result; + + /// Sends transaction; will block for 20s to try to return the + /// transaction hash. + /// If it cannot yet be signed, it will return a transaction ID for + /// later use with check_transaction. + fn send_transaction(&self, _: Params, _: Ready); + + /// Posts transaction asynchronously. + /// Will return a transaction ID for later use with check_transaction. + fn post_transaction(&self, _: Params) -> Result; + + /// Checks the progress of a previously posted request (transaction/sign). + /// Should be given a valid send_transaction ID. + /// Returns the transaction hash, the zero hash (not yet available), + /// or the signature, + /// or an error. + fn check_request(&self, _: Params) -> Result; + + /// Decrypt some ECIES-encrypted message. + /// First parameter is the address with which it is encrypted, second is the ciphertext. + fn decrypt_message(&self, _: Params, _: Ready); + + /// Should be used to convert object to io delegate. + fn to_delegate(self) -> IoDelegate { + let mut delegate = IoDelegate::new(Arc::new(self)); + delegate.add_async_method("eth_sign", EthSigning::sign); + delegate.add_async_method("eth_sendTransaction", EthSigning::send_transaction); + delegate.add_async_method("ethcore_decryptMessage", EthSigning::decrypt_message); + + delegate.add_method("eth_postSign", EthSigning::post_sign); + delegate.add_method("eth_postTransaction", EthSigning::post_transaction); + delegate.add_method("eth_checkRequest", EthSigning::check_request); + delegate + } +} diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index 3ca11b65436..e804c55536e 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -18,6 +18,7 @@ pub mod web3; pub mod eth; +pub mod eth_signing; pub mod net; pub mod personal; pub mod ethcore; @@ -26,7 +27,8 @@ pub mod traces; pub mod rpc; pub use self::web3::Web3; -pub use self::eth::{Eth, EthFilter, EthSigning}; +pub use self::eth::{Eth, EthFilter}; +pub use self::eth_signing::EthSigning; pub use self::net::Net; pub use self::personal::{Personal, PersonalSigner}; pub use self::ethcore::Ethcore; @@ -34,4 +36,3 @@ pub use self::ethcore_set::EthcoreSet; pub use self::traces::Traces; pub use self::rpc::Rpc; - diff --git a/rpc/src/v1/types/confirmations.rs b/rpc/src/v1/types/confirmations.rs index c074df4431c..c5ef4efa98f 100644 --- a/rpc/src/v1/types/confirmations.rs +++ b/rpc/src/v1/types/confirmations.rs @@ -16,7 +16,7 @@ //! Types used in Confirmations queue (Trusted Signer) -use v1::types::{U256, TransactionRequest, H160, H256}; +use v1::types::{U256, TransactionRequest, H160, H256, Bytes}; use v1::helpers; @@ -47,6 +47,15 @@ pub struct SignRequest { pub hash: H256, } +/// Decrypt request +#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)] +pub struct DecryptRequest { + /// Address + pub address: H160, + /// Message to decrypt + pub msg: Bytes, +} + /// Confirmation payload, i.e. the thing to be confirmed #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize)] pub enum ConfirmationPayload { @@ -56,6 +65,9 @@ pub enum ConfirmationPayload { /// Signature #[serde(rename="sign")] Sign(SignRequest), + /// Decryption + #[serde(rename="decrypt")] + Decrypt(DecryptRequest), } impl From for ConfirmationPayload { @@ -66,6 +78,10 @@ impl From for ConfirmationPayload { address: address.into(), hash: hash.into(), }), + helpers::ConfirmationPayload::Decrypt(address, msg) => ConfirmationPayload::Decrypt(DecryptRequest { + address: address.into(), + msg: msg.into(), + }), } } } diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 3d0e768967b..43b6bd84a47 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -20,11 +20,12 @@ ethcore-util = { path = "../util" } ethcore-io = { path = "../util/io" } ethcore-rpc = { path = "../rpc" } ethcore-devtools = { path = "../devtools" } +parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true} parity-dapps-signer = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true} clippy = { version = "0.0.90", optional = true} [features] dev = ["clippy"] -ui = ["parity-dapps-signer"] +ui = ["parity-dapps", "parity-dapps-signer"] use-precompiled-js = ["parity-dapps-signer/use-precompiled-js"] diff --git a/signer/src/lib.rs b/signer/src/lib.rs index abe84a03ec2..630cefb829d 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -54,6 +54,8 @@ extern crate jsonrpc_core; extern crate ws; #[cfg(feature = "ui")] extern crate parity_dapps_signer as signer; +#[cfg(feature = "ui")] +extern crate parity_dapps as dapps; #[cfg(test)] extern crate ethcore_devtools as devtools; diff --git a/signer/src/ws_server/session.rs b/signer/src/ws_server/session.rs index afc6606d7e7..1e3a9a7d2e4 100644 --- a/signer/src/ws_server/session.rs +++ b/signer/src/ws_server/session.rs @@ -26,21 +26,39 @@ use util::{H256, Mutex, version}; #[cfg(feature = "ui")] mod signer { - use signer; + use signer::SignerApp; + use dapps::{self, WebApp}; - pub fn handle(req: &str) -> Option { - signer::handle(req) + #[derive(Default)] + pub struct Handler { + signer: SignerApp, + } + + impl Handler { + pub fn handle(&self, req: &str) -> Option<&dapps::File> { + let file = match req { + "" | "/" => "index.html", + path => &path[1..], + }; + self.signer.file(file) + } } } #[cfg(not(feature = "ui"))] mod signer { pub struct File { - pub content: String, - pub mime: String, + pub content: &'static str, + pub content_type: &'static str, } - pub fn handle(_req: &str) -> Option { - None + #[derive(Default)] + pub struct Handler { + } + + impl Handler { + pub fn handle(&self, _req: &str) -> Option<&File> { + None + } } } @@ -107,6 +125,7 @@ pub struct Session { self_origin: String, authcodes_path: PathBuf, handler: Arc, + file_handler: Arc, } impl ws::Handler for Session { @@ -152,12 +171,12 @@ impl ws::Handler for Session { } // Otherwise try to serve a page. - Ok(signer::handle(req.resource()) + Ok(self.file_handler.handle(req.resource()) .map_or_else( // return 404 not found || error(ErrorType::NotFound, "Not found", "Requested file was not found.", None), // or serve the file - |f| add_headers(ws::Response::ok(f.content.into()), &f.mime) + |f| add_headers(ws::Response::ok_raw(f.content.to_vec()), f.content_type) )) } @@ -181,6 +200,7 @@ pub struct Factory { skip_origin_validation: bool, self_origin: String, authcodes_path: PathBuf, + file_handler: Arc, } impl Factory { @@ -190,6 +210,7 @@ impl Factory { skip_origin_validation: skip_origin_validation, self_origin: self_origin, authcodes_path: authcodes_path, + file_handler: Arc::new(signer::Handler::default()), } } } @@ -204,6 +225,7 @@ impl ws::Factory for Factory { skip_origin_validation: self.skip_origin_validation, self_origin: self.self_origin.clone(), authcodes_path: self.authcodes_path.clone(), + file_handler: self.file_handler.clone(), } } } From cceca916a1e64e7113533218d28022a2011032d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 15 Oct 2016 14:46:33 +0200 Subject: [PATCH 12/14] [frontport] CLI to specify queue ordering strategy (#2494) (#2623) * CLI to specify queue ordering strategy (#2494) * Alter gas priorities to include gas_price also * CLI options and tests * Adding ordering by gas * whitespace Conflicts: ethcore/src/miner/miner.rs ethcore/src/miner/mod.rs ethcore/src/miner/transaction_queue.rs parity/cli/usage.txt parity/configuration.rs * fix build --- ethcore/src/miner/miner.rs | 16 +- ethcore/src/miner/mod.rs | 2 +- ethcore/src/miner/transaction_queue.rs | 310 ++++++++++++++++++------- parity/cli/config.full.toml | 3 +- parity/cli/config.toml | 2 +- parity/cli/mod.rs | 11 +- parity/cli/usage.txt | 6 + parity/configuration.rs | 25 +- parity/helpers.rs | 11 +- parity/params.rs | 2 +- rpc/src/v1/tests/eth.rs | 3 +- 11 files changed, 288 insertions(+), 103 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 08d84b6378a..63bb367b64f 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -30,7 +30,7 @@ use transaction::{Action, SignedTransaction}; use receipt::{Receipt, RichReceipt}; use spec::Spec; use engines::Engine; -use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionOrigin}; +use miner::{MinerService, MinerStatus, TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin}; use miner::work_notify::WorkPoster; use client::TransactionImportResult; use miner::price_info::PriceInfo; @@ -76,6 +76,8 @@ pub struct MinerOptions { pub tx_gas_limit: U256, /// Maximum size of the transaction queue. pub tx_queue_size: usize, + /// Strategy to use for prioritizing transactions in the queue. + pub tx_queue_strategy: PrioritizationStrategy, /// Whether we should fallback to providing all the queue's transactions or just pending. pub pending_set: PendingSet, /// How many historical work packages can we store before running out? @@ -94,12 +96,13 @@ impl Default for MinerOptions { reseal_on_external_tx: false, reseal_on_own_tx: true, tx_gas_limit: !U256::zero(), - tx_queue_size: 2048, + tx_queue_size: 1024, + tx_queue_gas_limit: GasLimit::Auto, + tx_queue_strategy: PrioritizationStrategy::GasFactorAndGasPrice, pending_set: PendingSet::AlwaysQueue, reseal_min_period: Duration::from_secs(2), work_queue_size: 20, enable_resubmission: true, - tx_queue_gas_limit: GasLimit::Auto, } } } @@ -212,7 +215,9 @@ impl Miner { GasLimit::Fixed(ref limit) => *limit, _ => !U256::zero(), }; - let txq = Arc::new(Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, gas_limit, options.tx_gas_limit))); + let txq = Arc::new(Mutex::new(TransactionQueue::with_limits( + options.tx_queue_strategy, options.tx_queue_size, gas_limit, options.tx_gas_limit + ))); Miner { transaction_queue: txq, next_allowed_reseal: Mutex::new(Instant::now()), @@ -1029,7 +1034,7 @@ impl MinerService for Miner { mod tests { use std::time::Duration; - use super::super::MinerService; + use super::super::{MinerService, PrioritizationStrategy}; use super::*; use util::*; use ethkey::{Generator, Random}; @@ -1083,6 +1088,7 @@ mod tests { tx_gas_limit: !U256::zero(), tx_queue_size: 1024, tx_queue_gas_limit: GasLimit::None, + tx_queue_strategy: PrioritizationStrategy::GasFactorAndGasPrice, pending_set: PendingSet::AlwaysSealing, work_queue_size: 5, enable_resubmission: true, diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 8dfddf483a3..5fe8dbf44e7 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -47,7 +47,7 @@ mod transaction_queue; mod work_notify; mod price_info; -pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin}; +pub use self::transaction_queue::{TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin}; pub use self::miner::{Miner, MinerOptions, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit}; pub use self::external::{ExternalMiner, ExternalMinerService}; pub use client::TransactionImportResult; diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 15fe38236ed..9e47a846749 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -49,7 +49,7 @@ //! balance: U256::from(1_000_000), //! }; //! -//! let mut txq = TransactionQueue::new(); +//! let mut txq = TransactionQueue::default(); //! txq.add(st2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); //! txq.add(st1.clone(), &default_account_details, TransactionOrigin::External).unwrap(); //! @@ -130,11 +130,20 @@ struct TransactionOrder { /// (e.g. Tx(nonce:5), State(nonce:0) -> height: 5) /// High nonce_height = Low priority (processed later) nonce_height: U256, - /// Gas specified in the transaction. - gas: U256, /// Gas Price of the transaction. /// Low gas price = Low priority (processed later) gas_price: U256, + /// Gas usage priority factor. Usage depends on strategy. + /// Represents the linear increment in required gas price for heavy transactions. + /// + /// High gas limit + Low gas price = Low priority + /// High gas limit + High gas price = High priority + gas_factor: U256, + /// Gas (limit) of the transaction. Usage depends on strategy. + /// Low gas limit = High priority (processed earlier) + gas: U256, + /// Transaction ordering strategy + strategy: PrioritizationStrategy, /// Hash to identify associated transaction hash: H256, /// Origin of the transaction @@ -145,11 +154,15 @@ struct TransactionOrder { impl TransactionOrder { - fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self { + + fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256, min_gas_price: U256, strategy: PrioritizationStrategy) -> Self { + let factor = (tx.transaction.gas >> 15) * min_gas_price; TransactionOrder { nonce_height: tx.nonce() - base_nonce, - gas: tx.transaction.gas.clone(), gas_price: tx.transaction.gas_price, + gas: tx.transaction.gas, + gas_factor: factor, + strategy: strategy, hash: tx.hash(), origin: tx.origin, penalties: 0, @@ -197,11 +210,28 @@ impl Ord for TransactionOrder { return self.origin.cmp(&b.origin); } + match self.strategy { + PrioritizationStrategy::GasAndGasPrice => { + if self.gas != b.gas { + return self.gas.cmp(&b.gas); + } + }, + PrioritizationStrategy::GasFactorAndGasPrice => { + // avoiding overflows + // (gp1 - g1) > (gp2 - g2) <=> + // (gp1 + g2) > (gp2 + g1) + let f_a = self.gas_price + b.gas_factor; + let f_b = b.gas_price + self.gas_factor; + if f_a != f_b { + return f_b.cmp(&f_a); + } + }, + PrioritizationStrategy::GasPriceOnly => {}, + } + // Then compare gas_prices - let a_gas = self.gas_price; - let b_gas = b.gas_price; - if a_gas != b_gas { - return b_gas.cmp(&a_gas); + if self.gas_price != b.gas_price { + return b.gas_price.cmp(&self.gas_price); } // Compare hashes @@ -415,8 +445,32 @@ pub struct AccountDetails { /// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue. const GAS_LIMIT_HYSTERESIS: usize = 10; // (100/GAS_LIMIT_HYSTERESIS) % +/// Describes the strategy used to prioritize transactions in the queue. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum PrioritizationStrategy { + /// Use only gas price. Disregards the actual computation cost of the transaction. + /// i.e. Higher gas price = Higher priority + GasPriceOnly, + /// Use gas limit and then gas price. + /// i.e. Higher gas limit = Lower priority + GasAndGasPrice, + /// Calculate and use priority based on gas and gas price. + /// PRIORITY = GAS_PRICE - GAS/2^15 * MIN_GAS_PRICE + /// + /// Rationale: + /// Heavy transactions are paying linear cost (GAS * GAS_PRICE) + /// while the computation might be more expensive. + /// + /// i.e. + /// 1M gas tx with `gas_price=30*min` has the same priority + /// as 32k gas tx with `gas_price=min` + GasFactorAndGasPrice, +} + /// `TransactionQueue` implementation pub struct TransactionQueue { + /// Prioritization strategy for this queue + strategy: PrioritizationStrategy, /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) minimal_gas_price: U256, /// The maximum amount of gas any individual transaction may use. @@ -435,18 +489,18 @@ pub struct TransactionQueue { impl Default for TransactionQueue { fn default() -> Self { - TransactionQueue::new() + TransactionQueue::new(PrioritizationStrategy::GasPriceOnly) } } impl TransactionQueue { /// Creates new instance of this Queue - pub fn new() -> Self { - Self::with_limits(1024, !U256::zero(), !U256::zero()) + pub fn new(strategy: PrioritizationStrategy) -> Self { + Self::with_limits(strategy, 1024, !U256::zero(), !U256::zero()) } /// Create new instance of this Queue with specified limits - pub fn with_limits(limit: usize, gas_limit: U256, tx_gas_limit: U256) -> Self { + pub fn with_limits(strategy: PrioritizationStrategy, limit: usize, gas_limit: U256, tx_gas_limit: U256) -> Self { let current = TransactionSet { by_priority: BTreeSet::new(), by_address: Table::new(), @@ -464,6 +518,7 @@ impl TransactionQueue { }; TransactionQueue { + strategy: strategy, minimal_gas_price: U256::zero(), tx_gas_limit: tx_gas_limit, gas_limit: !U256::zero(), @@ -844,6 +899,7 @@ impl TransactionQueue { return Err(TransactionError::AlreadyImported); } + let min_gas_price = (self.minimal_gas_price, self.strategy); let address = tx.sender(); let nonce = tx.nonce(); let hash = tx.hash(); @@ -881,7 +937,7 @@ impl TransactionQueue { if nonce > next_nonce { // We have a gap - put to future. // Insert transaction (or replace old one with lower gas price) - try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.future, &mut self.by_hash))); + try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.future, &mut self.by_hash))); // Enforce limit in Future let removed = self.future.enforce_limit(&mut self.by_hash); // Return an error if this transaction was not imported because of limit. @@ -897,7 +953,7 @@ impl TransactionQueue { self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); // Replace transaction if any - try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash))); + try!(check_too_cheap(Self::replace_transaction(tx, state_nonce, min_gas_price, &mut self.current, &mut self.by_hash))); // Keep track of highest nonce stored in current let new_max = self.last_nonces.get(&address).map_or(nonce, |n| cmp::max(nonce, *n)); self.last_nonces.insert(address, new_max); @@ -934,8 +990,8 @@ impl TransactionQueue { /// /// Returns `true` if transaction actually got to the queue (`false` if there was already a transaction with higher /// gas_price) - fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, set: &mut TransactionSet, by_hash: &mut HashMap) -> bool { - let order = TransactionOrder::for_transaction(&tx, base_nonce); + fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, min_gas_price: (U256, PrioritizationStrategy), set: &mut TransactionSet, by_hash: &mut HashMap) -> bool { + let order = TransactionOrder::for_transaction(&tx, base_nonce, min_gas_price.0, min_gas_price.1); let hash = tx.hash(); let address = tx.sender(); let nonce = tx.nonce(); @@ -1015,12 +1071,12 @@ mod test { fn default_gas_val() -> U256 { 100_000.into() } fn default_gas_price() -> U256 { 1.into() } - fn new_unsigned_tx(nonce: U256, gas_price: U256) -> Transaction { + fn new_unsigned_tx(nonce: U256, gas: U256, gas_price: U256) -> Transaction { Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), - gas: default_gas_val(), + gas: gas, gas_price: gas_price, nonce: nonce } @@ -1028,7 +1084,12 @@ mod test { fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction { let keypair = Random.generate().unwrap(); - new_unsigned_tx(nonce, gas_price).sign(keypair.secret()) + new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret()) + } + + fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction { + let keypair = Random.generate().unwrap(); + new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret()) } fn new_tx_default() -> SignedTransaction { @@ -1043,8 +1104,8 @@ mod test { } fn new_tx_pair(nonce: U256, gas_price: U256, nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { - let tx1 = new_unsigned_tx(nonce, gas_price); - let tx2 = new_unsigned_tx(nonce + nonce_increment, gas_price + gas_price_increment); + let tx1 = new_unsigned_tx(nonce, default_gas_val(), gas_price); + let tx2 = new_unsigned_tx(nonce + nonce_increment, default_gas_val(), gas_price + gas_price_increment); let keypair = Random.generate().unwrap(); let secret = &keypair.secret(); @@ -1054,8 +1115,8 @@ mod test { /// Returns two consecutive transactions, both with increased gas price fn new_tx_pair_with_gas_price_increment(gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { let gas = default_gas_price() + gas_price_increment; - let tx1 = new_unsigned_tx(default_nonce(), gas); - let tx2 = new_unsigned_tx(default_nonce() + 1.into(), gas); + let tx1 = new_unsigned_tx(default_nonce(), default_gas_val(), gas); + let tx2 = new_unsigned_tx(default_nonce() + 1.into(), default_gas_val(), gas); let keypair = Random.generate().unwrap(); let secret = &keypair.secret(); @@ -1082,17 +1143,21 @@ mod test { assert_eq!(TransactionOrigin::External.cmp(&TransactionOrigin::RetractedBlock), Ordering::Greater); } + fn transaction_order(tx: &VerifiedTransaction, nonce: U256) -> TransactionOrder { + TransactionOrder::for_transaction(tx, nonce, 0.into(), PrioritizationStrategy::GasPriceOnly) + } + #[test] fn should_return_correct_nonces_when_dropped_because_of_limit() { // given - let mut txq = TransactionQueue::with_limits(2, !U256::zero(), !U256::zero()); + let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 2, !U256::zero(), !U256::zero()); let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into()); let sender = tx1.sender().unwrap(); let nonce = tx1.nonce; txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap(); txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); assert_eq!(txq.status().pending, 2); - assert_eq!(txq.last_nonce(&sender), Some(nonce + U256::one())); + assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into())); // when let tx = new_tx(123.into(), 1.into()); @@ -1138,9 +1203,9 @@ mod test { x }; // Insert both transactions - let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + let order1 = transaction_order(&tx1, U256::zero()); set.insert(tx1.sender(), tx1.nonce(), order1.clone()); - let order2 = TransactionOrder::for_transaction(&tx2, U256::zero()); + let order2 = transaction_order(&tx2, U256::zero()); set.insert(tx2.sender(), tx2.nonce(), order2.clone()); assert_eq!(set.by_priority.len(), 2); assert_eq!(set.by_address.len(), 2); @@ -1181,7 +1246,7 @@ mod test { x }; // Insert both transactions - let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + let order1 = transaction_order(&tx1, U256::zero()); set.insert(tx1.sender(), tx1.nonce(), order1.clone()); assert_eq!(set.by_priority.len(), 1); assert_eq!(set.by_address.len(), 1); @@ -1189,7 +1254,7 @@ mod test { assert_eq!(*set.by_gas_price.iter().next().unwrap().0, 1.into()); assert_eq!(set.by_gas_price.iter().next().unwrap().1.len(), 1); // Two different orders (imagine nonce changed in the meantime) - let order2 = TransactionOrder::for_transaction(&tx2, U256::one()); + let order2 = transaction_order(&tx2, U256::one()); set.insert(tx2.sender(), tx2.nonce(), order2.clone()); assert_eq!(set.by_priority.len(), 1); assert_eq!(set.by_address.len(), 1); @@ -1218,10 +1283,10 @@ mod test { }; let tx = new_tx_default(); let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap(); - let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none()); let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External).unwrap(); - let order2 = TransactionOrder::for_transaction(&tx2, U256::zero()); + let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some()); } @@ -1238,7 +1303,7 @@ mod test { assert_eq!(set.gas_price_entry_limit(), 0.into()); let tx = new_tx_default(); let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap(); - let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none()); assert_eq!(set.gas_price_entry_limit(), 2.into()); } @@ -1246,7 +1311,7 @@ mod test { #[test] fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_similar_tx_pair(); let prev_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance: !U256::zero() }; @@ -1271,7 +1336,7 @@ mod test { #[test] fn should_move_all_transactions_from_future() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 1.into()); let prev_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance: !U256::zero() }; @@ -1297,7 +1362,7 @@ mod test { #[test] fn should_import_tx() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); // when @@ -1309,10 +1374,77 @@ mod test { assert_eq!(stats.pending, 1); } + #[test] + fn should_order_by_gas() { + // given + let mut txq = TransactionQueue::new(PrioritizationStrategy::GasAndGasPrice); + let tx1 = new_tx_with_gas(50000.into(), 40.into()); + let tx2 = new_tx_with_gas(40000.into(), 30.into()); + let tx3 = new_tx_with_gas(30000.into(), 10.into()); + let tx4 = new_tx_with_gas(50000.into(), 20.into()); + txq.set_minimal_gas_price(15.into()); + + // when + let res1 = txq.add(tx1, &default_account_details, TransactionOrigin::External); + let res2 = txq.add(tx2, &default_account_details, TransactionOrigin::External); + let res3 = txq.add(tx3, &default_account_details, TransactionOrigin::External); + let res4 = txq.add(tx4, &default_account_details, TransactionOrigin::External); + + // then + assert_eq!(res1.unwrap(), TransactionImportResult::Current); + assert_eq!(res2.unwrap(), TransactionImportResult::Current); + assert_eq!(unwrap_tx_err(res3), TransactionError::InsufficientGasPrice { + minimal: U256::from(15), + got: U256::from(10), + }); + assert_eq!(res4.unwrap(), TransactionImportResult::Current); + let stats = txq.status(); + assert_eq!(stats.pending, 3); + assert_eq!(txq.top_transactions()[0].gas, 40000.into()); + assert_eq!(txq.top_transactions()[1].gas, 50000.into()); + assert_eq!(txq.top_transactions()[2].gas, 50000.into()); + assert_eq!(txq.top_transactions()[1].gas_price, 40.into()); + assert_eq!(txq.top_transactions()[2].gas_price, 20.into()); + } + + #[test] + fn should_order_by_gas_factor() { + // given + let mut txq = TransactionQueue::new(PrioritizationStrategy::GasFactorAndGasPrice); + + let tx1 = new_tx_with_gas(150_000.into(), 40.into()); + let tx2 = new_tx_with_gas(40_000.into(), 16.into()); + let tx3 = new_tx_with_gas(30_000.into(), 15.into()); + let tx4 = new_tx_with_gas(150_000.into(), 62.into()); + txq.set_minimal_gas_price(15.into()); + + // when + let res1 = txq.add(tx1, &default_account_details, TransactionOrigin::External); + let res2 = txq.add(tx2, &default_account_details, TransactionOrigin::External); + let res3 = txq.add(tx3, &default_account_details, TransactionOrigin::External); + let res4 = txq.add(tx4, &default_account_details, TransactionOrigin::External); + + // then + assert_eq!(res1.unwrap(), TransactionImportResult::Current); + assert_eq!(res2.unwrap(), TransactionImportResult::Current); + assert_eq!(res3.unwrap(), TransactionImportResult::Current); + assert_eq!(res4.unwrap(), TransactionImportResult::Current); + let stats = txq.status(); + assert_eq!(stats.pending, 4); + assert_eq!(txq.top_transactions()[0].gas, 30_000.into()); + assert_eq!(txq.top_transactions()[1].gas, 150_000.into()); + assert_eq!(txq.top_transactions()[2].gas, 40_000.into()); + assert_eq!(txq.top_transactions()[3].gas, 150_000.into()); + assert_eq!(txq.top_transactions()[0].gas_price, 15.into()); + assert_eq!(txq.top_transactions()[1].gas_price, 62.into()); + assert_eq!(txq.top_transactions()[2].gas_price, 16.into()); + assert_eq!(txq.top_transactions()[3].gas_price, 40.into()); + } + #[test] fn gas_limit_should_never_overflow() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); txq.set_gas_limit(U256::zero()); assert_eq!(txq.gas_limit, U256::zero()); @@ -1326,7 +1458,7 @@ mod test { #[test] fn should_not_import_transaction_above_gas_limit() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); let gas = tx.gas; let limit = gas / U256::from(2); @@ -1349,7 +1481,7 @@ mod test { #[test] fn should_drop_transactions_from_senders_without_balance() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); let account = |a: &Address| AccountDetails { nonce: default_account_details(a).nonce, @@ -1372,7 +1504,7 @@ mod test { #[test] fn should_not_import_transaction_below_min_gas_price_threshold_if_external() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); txq.set_minimal_gas_price(tx.gas_price + U256::one()); @@ -1392,7 +1524,7 @@ mod test { #[test] fn should_import_transaction_below_min_gas_price_threshold_if_local() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); txq.set_minimal_gas_price(tx.gas_price + U256::one()); @@ -1411,8 +1543,8 @@ mod test { use rlp::{self, RlpStream, Stream}; // given - let mut txq = TransactionQueue::new(); - let tx = new_unsigned_tx(123.into(), 1.into()); + let mut txq = TransactionQueue::default(); + let tx = new_unsigned_tx(123.into(), 100.into(), 1.into()); let stx = { let mut s = RlpStream::new_list(9); s.append(&tx.nonce); @@ -1436,7 +1568,7 @@ mod test { #[test] fn should_import_txs_from_same_sender() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); @@ -1454,7 +1586,7 @@ mod test { #[test] fn should_prioritize_local_transactions_within_same_nonce_height() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); // the second one has same nonce but higher `gas_price` let (_, tx2) = new_similar_tx_pair(); @@ -1475,7 +1607,7 @@ mod test { #[test] fn should_prioritize_reimported_transactions_within_same_nonce_height() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); // the second one has same nonce but higher `gas_price` let (_, tx2) = new_similar_tx_pair(); @@ -1496,7 +1628,7 @@ mod test { #[test] fn should_not_prioritize_local_transactions_with_different_nonce_height() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); // when @@ -1514,7 +1646,7 @@ mod test { fn should_penalize_transactions_from_sender_in_future() { // given let prev_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance: !U256::zero() }; - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); // txa, txb - slightly bigger gas price to have consistent ordering let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); @@ -1543,7 +1675,7 @@ mod test { #[test] fn should_penalize_transactions_from_sender() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); // txa, txb - slightly bigger gas price to have consistent ordering let (txa, txb) = new_tx_pair_default(1.into(), 0.into()); let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); @@ -1576,7 +1708,7 @@ mod test { #[test] fn should_return_pending_hashes() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); @@ -1594,7 +1726,7 @@ mod test { #[test] fn should_put_transaction_to_futures_if_gap_detected() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(2.into(), 0.into()); @@ -1620,7 +1752,7 @@ mod test { !U256::zero() }; let next2_nonce = default_nonce() + U256::from(3); - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); txq.add(tx.clone(), &prev_nonce, TransactionOrigin::External).unwrap(); @@ -1639,12 +1771,12 @@ mod test { #[test] fn should_move_transactions_if_gap_filled() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let kp = Random.generate().unwrap(); let secret = kp.secret(); - let tx = new_unsigned_tx(123.into(), 1.into()).sign(secret); - let tx1 = new_unsigned_tx(124.into(), 1.into()).sign(secret); - let tx2 = new_unsigned_tx(125.into(), 1.into()).sign(secret); + let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret); + let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret); + let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret); txq.add(tx, &default_account_details, TransactionOrigin::External).unwrap(); assert_eq!(txq.status().pending, 1); @@ -1666,7 +1798,7 @@ mod test { #[test] fn should_remove_transaction() { // given - let mut txq2 = TransactionQueue::new(); + let mut txq2 = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(3.into(), 0.into()); txq2.add(tx.clone(), &default_account_details, TransactionOrigin::External).unwrap(); txq2.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); @@ -1687,7 +1819,7 @@ mod test { #[test] fn should_move_transactions_to_future_if_gap_introduced() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let tx3 = new_tx_default(); txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); @@ -1708,7 +1840,7 @@ mod test { #[test] fn should_clear_queue() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); // add @@ -1728,7 +1860,7 @@ mod test { #[test] fn should_drop_old_transactions_when_hitting_the_limit() { // given - let mut txq = TransactionQueue::with_limits(1, !U256::zero(), !U256::zero()); + let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let sender = tx.sender().unwrap(); let nonce = tx.nonce; @@ -1749,7 +1881,7 @@ mod test { #[test] fn should_limit_future_transactions() { - let mut txq = TransactionQueue::with_limits(1, !U256::zero(), !U256::zero()); + let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero()); txq.current.set_limit(10); let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into()); let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into()); @@ -1768,19 +1900,20 @@ mod test { #[test] fn should_limit_by_gas() { - let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero()); + let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero()); let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); - txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).ok(); - txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).ok(); - txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).ok(); - txq.add(tx4.clone(), &default_account_details, TransactionOrigin::External).ok(); + txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap(); + txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); + txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).unwrap(); + // limited by gas + txq.add(tx4.clone(), &default_account_details, TransactionOrigin::External).unwrap_err(); assert_eq!(txq.status().pending, 2); } #[test] fn should_keep_own_transactions_above_gas_limit() { - let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero()); + let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero()); let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); let (tx5, tx6) = new_tx_pair_default(U256::from(1), U256::from(2)); @@ -1796,10 +1929,10 @@ mod test { #[test] fn should_drop_transactions_with_old_nonces() { - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); let last_nonce = tx.nonce + U256::one(); - let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() }; + let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() }; // when let res = txq.add(tx, &fetch_last_nonce, TransactionOrigin::External); @@ -1816,7 +1949,7 @@ mod test { // given let nonce = |a: &Address| AccountDetails { nonce: default_account_details(a).nonce + U256::one(), balance: !U256::zero() }; - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); assert_eq!(txq.status().future, 1); @@ -1835,7 +1968,7 @@ mod test { #[test] fn should_accept_same_transaction_twice_if_removed() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap(); txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); @@ -1856,7 +1989,7 @@ mod test { #[test] fn should_not_move_to_future_if_state_nonce_is_higher() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let tx3 = new_tx_default(); txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).unwrap(); @@ -1879,9 +2012,9 @@ mod test { fn should_replace_same_transaction_when_has_higher_fee() { init_log(); // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let keypair = Random.generate().unwrap(); - let tx = new_unsigned_tx(123.into(), 1.into()).sign(keypair.secret()); + let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret()); let tx2 = { let mut tx2 = (*tx).clone(); tx2.gas_price = U256::from(200); @@ -1902,9 +2035,9 @@ mod test { #[test] fn should_replace_same_transaction_when_importing_to_futures() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let keypair = Random.generate().unwrap(); - let tx0 = new_unsigned_tx(123.into(), 1.into()).sign(keypair.secret()); + let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret()); let tx1 = { let mut tx1 = (*tx0).clone(); tx1.nonce = U256::from(124); @@ -1936,7 +2069,7 @@ mod test { !U256::zero() }; let next_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce + U256::one(), balance: !U256::zero() }; - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); txq.add(tx1.clone(), &previous_nonce, TransactionOrigin::External).unwrap(); txq.add(tx2, &previous_nonce, TransactionOrigin::External).unwrap(); @@ -1954,7 +2087,7 @@ mod test { #[test] fn should_return_none_when_transaction_from_given_address_does_not_exist() { // given - let txq = TransactionQueue::new(); + let txq = TransactionQueue::default(); // then assert_eq!(txq.last_nonce(&Address::default()), None); @@ -1963,7 +2096,7 @@ mod test { #[test] fn should_return_correct_nonce_when_transactions_from_given_address_exist() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let tx = new_tx_default(); let from = tx.sender().unwrap(); let nonce = tx.nonce; @@ -1979,7 +2112,7 @@ mod test { #[test] fn should_remove_old_transaction_even_if_newer_transaction_was_not_known() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); let (nonce1, nonce2) = (tx1.nonce, tx2.nonce); let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() }; @@ -1997,7 +2130,7 @@ mod test { #[test] fn should_return_valid_last_nonce_after_remove_all() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx1, tx2) = new_tx_pair_default(4.into(), 0.into()); let sender = tx1.sender().unwrap(); let (nonce1, nonce2) = (tx1.nonce, tx2.nonce); @@ -2021,7 +2154,7 @@ mod test { #[test] fn should_return_true_if_there_is_local_transaction_pending() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); assert_eq!(txq.has_local_pending_transactions(), false); @@ -2037,7 +2170,7 @@ mod test { #[test] fn should_keep_right_order_in_future() { // given - let mut txq = TransactionQueue::with_limits(1, !U256::zero(), !U256::zero()); + let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 1, !U256::zero(), !U256::zero()); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); let prev_nonce = |a: &Address| AccountDetails { nonce: default_account_details(a).nonce - U256::one(), balance: default_account_details(a).balance }; @@ -2054,15 +2187,16 @@ mod test { #[test] fn should_return_correct_last_nonce() { // given - let mut txq = TransactionQueue::new(); + let mut txq = TransactionQueue::default(); let (tx1, tx2, tx2_2, tx3) = { let keypair = Random.generate().unwrap(); let secret = &keypair.secret(); let nonce = 123.into(); - let tx = new_unsigned_tx(nonce, 1.into()); - let tx2 = new_unsigned_tx(nonce + 1.into(), 1.into()); - let tx2_2 = new_unsigned_tx(nonce + 1.into(), 5.into()); - let tx3 = new_unsigned_tx(nonce + 2.into(), 1.into()); + let gas = default_gas_val(); + let tx = new_unsigned_tx(nonce, gas, 1.into()); + let tx2 = new_unsigned_tx(nonce + 1.into(), gas, 1.into()); + let tx2_2 = new_unsigned_tx(nonce + 1.into(), gas, 5.into()); + let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into()); (tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret)) diff --git a/parity/cli/config.full.toml b/parity/cli/config.full.toml index 3a9531bcff2..b71bd936121 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -67,8 +67,9 @@ usd_per_eth = "auto" price_update_period = "hourly" gas_floor_target = "4700000" gas_cap = "6283184" -tx_queue_size = 2048 +tx_queue_size = 1024 tx_queue_gas = "auto" +tx_queue_strategy = "gas_factor" tx_gas_limit = "6283184" extra_data = "Parity" remove_solved = false diff --git a/parity/cli/config.toml b/parity/cli/config.toml index d9608640c89..02ff9c0dd85 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -40,7 +40,7 @@ force_sealing = true reseal_on_txs = "all" reseal_min_period = 4000 price_update_period = "hourly" -tx_queue_size = 2048 +tx_queue_size = 1024 tx_queue_gas = "auto" [footprint] diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index c4ec4135cf9..d4398b6f5b9 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -193,10 +193,12 @@ usage! { or |c: &Config| otry!(c.mining).gas_cap.clone(), flag_extra_data: Option = None, or |c: &Config| otry!(c.mining).extra_data.clone().map(Some), - flag_tx_queue_size: usize = 2048usize, + flag_tx_queue_size: usize = 1024usize, or |c: &Config| otry!(c.mining).tx_queue_size.clone(), flag_tx_queue_gas: String = "auto", or |c: &Config| otry!(c.mining).tx_queue_gas.clone(), + flag_tx_queue_strategy: String = "gas_factor", + or |c: &Config| otry!(c.mining).tx_queue_strategy.clone(), flag_remove_solved: bool = false, or |c: &Config| otry!(c.mining).remove_solved.clone(), flag_notify_work: Option = None, @@ -355,6 +357,7 @@ struct Mining { extra_data: Option, tx_queue_size: Option, tx_queue_gas: Option, + tx_queue_strategy: Option, remove_solved: Option, notify_work: Option>, } @@ -531,8 +534,9 @@ mod tests { flag_gas_floor_target: "4700000".into(), flag_gas_cap: "6283184".into(), flag_extra_data: Some("Parity".into()), - flag_tx_queue_size: 2048usize, + flag_tx_queue_size: 1024usize, flag_tx_queue_gas: "auto".into(), + flag_tx_queue_strategy: "gas_factor".into(), flag_remove_solved: false, flag_notify_work: Some("http://localhost:3001".into()), @@ -684,8 +688,9 @@ mod tests { price_update_period: Some("hourly".into()), gas_floor_target: None, gas_cap: None, - tx_queue_size: Some(2048), + tx_queue_size: Some(1024), tx_queue_gas: Some("auto".into()), + tx_queue_strategy: None, tx_gas_limit: None, extra_data: None, remove_solved: None, diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index 4f416e10db4..736af583459 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -188,6 +188,12 @@ Sealing/Mining Options: the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit. (default: {flag_tx_queue_gas}). + --tx-queue-strategy S Prioritization strategy used to order transactions + in the queue. S may be: + gas - Prioritize txs with low gas limit; + gas_price - Prioritize txs with high gas price; + gas_factor - Prioritize txs using gas price + and gas limit ratio (default: {flag_tx_queue_strategy}). --remove-solved Move solved blocks from the work package queue instead of cloning them. This gives a slightly faster import speed, but means that extra solutions diff --git a/parity/configuration.rs b/parity/configuration.rs index 5303b12019e..9043a814fce 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -30,7 +30,7 @@ use rpc::{IpcConfiguration, HttpConfiguration}; use ethcore_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, -geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit}; +geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras}; use ethcore_logger::Config as LogConfig; use dir::Directories; @@ -360,6 +360,7 @@ impl Configuration { }, tx_queue_size: self.args.flag_tx_queue_size, tx_queue_gas_limit: try!(to_gas_limit(&self.args.flag_tx_queue_gas)), + tx_queue_strategy: try!(to_queue_strategy(&self.args.flag_tx_queue_strategy)), pending_set: try!(to_pending_set(&self.args.flag_relay_set)), reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period), work_queue_size: self.args.flag_work_queue_size, @@ -647,6 +648,7 @@ mod tests { use cli::Args; use ethcore_rpc::NetworkSettings; use ethcore::client::{VMType, BlockID}; + use ethcore::miner::{MinerOptions, PrioritizationStrategy}; use helpers::{replace_home, default_network_config}; use run::RunCmd; use signer::Configuration as SignerConfiguration; @@ -830,6 +832,27 @@ mod tests { })); } + #[test] + fn should_parse_mining_options() { + // given + let mut mining_options = MinerOptions::default(); + + // when + let conf0 = parse(&["parity"]); + let conf1 = parse(&["parity", "--tx-queue-strategy", "gas_factor"]); + let conf2 = parse(&["parity", "--tx-queue-strategy", "gas_price"]); + let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]); + + // then + assert_eq!(conf0.miner_options().unwrap(), mining_options); + mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice; + assert_eq!(conf1.miner_options().unwrap(), mining_options); + mining_options.tx_queue_strategy = PrioritizationStrategy::GasPriceOnly; + assert_eq!(conf2.miner_options().unwrap(), mining_options); + mining_options.tx_queue_strategy = PrioritizationStrategy::GasAndGasPrice; + assert_eq!(conf3.miner_options().unwrap(), mining_options); + } + #[test] fn should_parse_network_settings() { // given diff --git a/parity/helpers.rs b/parity/helpers.rs index c8a985105c2..af947329b65 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -22,7 +22,7 @@ use std::fs::File; use util::{clean_0x, U256, Uint, Address, path, CompactionProfile}; use util::journaldb::Algorithm; use ethcore::client::{Mode, BlockID, VMType, DatabaseCompactionProfile, ClientConfig}; -use ethcore::miner::{PendingSet, GasLimit}; +use ethcore::miner::{PendingSet, GasLimit, PrioritizationStrategy}; use cache::CacheConfig; use dir::DatabaseDirectories; use upgrade::upgrade; @@ -101,6 +101,15 @@ pub fn to_gas_limit(s: &str) -> Result { } } +pub fn to_queue_strategy(s: &str) -> Result { + match s { + "gas" => Ok(PrioritizationStrategy::GasAndGasPrice), + "gas_price" => Ok(PrioritizationStrategy::GasPriceOnly), + "gas_factor" => Ok(PrioritizationStrategy::GasFactorAndGasPrice), + other => Err(format!("Invalid queue strategy: {}", other)), + } +} + pub fn to_address(s: Option) -> Result { match s { Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)), diff --git a/parity/params.rs b/parity/params.rs index ee3038ebfac..faba029b2b8 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -206,7 +206,7 @@ impl Default for MinerExtras { extra_data: version_data(), gas_floor_target: U256::from(4_700_000), gas_ceil_target: U256::from(6_283_184), - transactions_limit: 2048, + transactions_limit: 1024, } } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 1dfe9796858..5d748155131 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -24,7 +24,7 @@ use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::views::BlockView; use ethcore::ethereum; -use ethcore::miner::{MinerOptions, GasPricer, MinerService, ExternalMiner, Miner, PendingSet, GasLimit}; +use ethcore::miner::{MinerOptions, GasPricer, MinerService, ExternalMiner, Miner, PendingSet, PrioritizationStrategy, GasLimit}; use ethcore::account_provider::AccountProvider; use devtools::RandomTempPath; use util::Hashable; @@ -59,6 +59,7 @@ fn miner_service(spec: &Spec, accounts: Arc) -> Arc { reseal_on_own_tx: true, tx_queue_size: 1024, tx_gas_limit: !U256::zero(), + tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, tx_queue_gas_limit: GasLimit::None, pending_set: PendingSet::SealingOrElseQueue, reseal_min_period: Duration::from_secs(0), From 709f00ceb7566a81f3ad9fa6abc96eb995677e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 16 Oct 2016 00:20:11 +0200 Subject: [PATCH 13/14] Fixing compilation without default features (#2638) * Fixing compilation without default features * Removing unused import --- rpc/src/v1/impls/ethcore.rs | 1 - signer/src/ws_server/session.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index 33123ddd5d9..b430a710c59 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -36,7 +36,6 @@ use v1::traits::Ethcore; use v1::types::{Bytes, U256, H160, H256, H512, Peers, Transaction, RpcSettings}; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::dispatch::DEFAULT_MAC; -use v1::helpers::params::expect_no_params; use v1::helpers::auto_args::Ready; /// Ethcore implementation. diff --git a/signer/src/ws_server/session.rs b/signer/src/ws_server/session.rs index 1e3a9a7d2e4..14c619a2851 100644 --- a/signer/src/ws_server/session.rs +++ b/signer/src/ws_server/session.rs @@ -47,7 +47,7 @@ mod signer { #[cfg(not(feature = "ui"))] mod signer { pub struct File { - pub content: &'static str, + pub content: &'static [u8], pub content_type: &'static str, } From b5c65e3df59027a12d11d772e57132990f2ce19d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 16 Oct 2016 13:44:56 +0200 Subject: [PATCH 14/14] Fix up ETC EIP-150 transition to 2,500,000. (#2636) --- ethcore/res/ethereum/classic.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index 35a2cbed944..5d951752f9a 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -11,7 +11,7 @@ "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x118c30", - "eip150Transition": "0x7fffffffffffffff" + "eip150Transition": "0x2625a0" } } },