Merge remote-tracking branch 'origin/master' into check-updates
This commit is contained in:
commit
0a494962e4
@ -422,10 +422,10 @@ test-rust-stable:
|
|||||||
image: ethcore/rust:stable
|
image: ethcore/rust:stable
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v ^js/ | wc -l)
|
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||||
script:
|
script:
|
||||||
- export RUST_BACKTRACE=1
|
- export RUST_BACKTRACE=1
|
||||||
- if [ "$RUST_FILES_MODIFIED" = 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
- rust-stable
|
- rust-stable
|
||||||
@ -435,9 +435,9 @@ js-test:
|
|||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
- if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
||||||
script:
|
script:
|
||||||
- if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "Skipping JS lint since no JS files modified."; else ./js/scripts/lint.sh && ./js/scripts/test.sh && ./js/scripts/build.sh; fi
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS lint since no JS files modified."; else ./js/scripts/lint.sh && ./js/scripts/test.sh && ./js/scripts/build.sh; fi
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
- rust-stable
|
- rust-stable
|
||||||
@ -480,9 +480,9 @@ js-release:
|
|||||||
before_script:
|
before_script:
|
||||||
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
- echo $JS_FILES_MODIFIED
|
- echo $JS_FILES_MODIFIED
|
||||||
- if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
||||||
script:
|
script:
|
||||||
- echo $JS_FILES_MODIFIED
|
- echo $JS_FILES_MODIFIED
|
||||||
- if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "Skipping JS rebuild since no JS files modified."; else ./js/scripts/build.sh && ./js/scripts/release.sh; fi
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS rebuild since no JS files modified."; else ./js/scripts/build.sh && ./js/scripts/release.sh; fi
|
||||||
tags:
|
tags:
|
||||||
- javascript
|
- javascript
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1293,7 +1293,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/ethcore/js-precompiled.git#3d3b2f9e8e8b0fd62c172240bfd001a317cf2979"
|
source = "git+https://github.com/ethcore/js-precompiled.git#f982c84ac216cc4f99d056c912e205bcf9341602"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -170,9 +170,6 @@
|
|||||||
"enode://cadc6e573b6bc2a9128f2f635ac0db3353e360b56deef239e9be7e7fce039502e0ec670b595f6288c0d2116812516ad6b6ff8d5728ff45eba176989e40dead1e@37.128.191.230:30303",
|
"enode://cadc6e573b6bc2a9128f2f635ac0db3353e360b56deef239e9be7e7fce039502e0ec670b595f6288c0d2116812516ad6b6ff8d5728ff45eba176989e40dead1e@37.128.191.230:30303",
|
||||||
"enode://595a9a06f8b9bc9835c8723b6a82105aea5d55c66b029b6d44f229d6d135ac3ecdd3e9309360a961ea39d7bee7bac5d03564077a4e08823acc723370aace65ec@46.20.235.22:30303",
|
"enode://595a9a06f8b9bc9835c8723b6a82105aea5d55c66b029b6d44f229d6d135ac3ecdd3e9309360a961ea39d7bee7bac5d03564077a4e08823acc723370aace65ec@46.20.235.22:30303",
|
||||||
"enode://029178d6d6f9f8026fc0bc17d5d1401aac76ec9d86633bba2320b5eed7b312980c0a210b74b20c4f9a8b0b2bf884b111fa9ea5c5f916bb9bbc0e0c8640a0f56c@216.158.85.185:30303",
|
"enode://029178d6d6f9f8026fc0bc17d5d1401aac76ec9d86633bba2320b5eed7b312980c0a210b74b20c4f9a8b0b2bf884b111fa9ea5c5f916bb9bbc0e0c8640a0f56c@216.158.85.185:30303",
|
||||||
"enode://84f5d5957b4880a8b0545e32e05472318898ad9fc8ebe1d56c90c12334a98e12351eccfdf3a2bf72432ac38b57e9d348400d17caa083879ade3822390f89773f@10.1.52.78:30303",
|
|
||||||
"enode://f90dc9b9bf7b8db97726b7849e175f1eb2707f3d8f281c929336e398dd89b0409fc6aeceb89e846278e9d3ecc3857cebfbe6758ff352ece6fe5d42921ee761db@10.1.173.87:30303",
|
|
||||||
"enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@10.3.149.199:30303",
|
|
||||||
"enode://fdd1b9bb613cfbc200bba17ce199a9490edc752a833f88d4134bf52bb0d858aa5524cb3ec9366c7a4ef4637754b8b15b5dc913e4ed9fdb6022f7512d7b63f181@212.47.247.103:30303",
|
"enode://fdd1b9bb613cfbc200bba17ce199a9490edc752a833f88d4134bf52bb0d858aa5524cb3ec9366c7a4ef4637754b8b15b5dc913e4ed9fdb6022f7512d7b63f181@212.47.247.103:30303",
|
||||||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
||||||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
||||||
|
@ -1092,20 +1092,6 @@ impl MinerService for Miner {
|
|||||||
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
||||||
trace!(target: "miner", "chain_new_blocks");
|
trace!(target: "miner", "chain_new_blocks");
|
||||||
|
|
||||||
fn fetch_transactions(chain: &MiningBlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
|
|
||||||
let block = chain
|
|
||||||
.block(BlockId::Hash(*hash))
|
|
||||||
// Client should send message after commit to db and inserting to chain.
|
|
||||||
.expect("Expected in-chain blocks.");
|
|
||||||
let block = BlockView::new(&block);
|
|
||||||
let txs = block.transactions();
|
|
||||||
// populate sender
|
|
||||||
for tx in &txs {
|
|
||||||
let _sender = tx.sender();
|
|
||||||
}
|
|
||||||
txs
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
||||||
// should be still available in the queue.
|
// should be still available in the queue.
|
||||||
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
||||||
@ -1116,10 +1102,18 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
// Then import all transactions...
|
// Then import all transactions...
|
||||||
{
|
{
|
||||||
let out_of_chain = retracted
|
retracted.par_iter()
|
||||||
.par_iter()
|
.map(|hash| {
|
||||||
.map(|h| fetch_transactions(chain, h));
|
let block = chain.block(BlockId::Hash(*hash))
|
||||||
out_of_chain.for_each(|txs| {
|
.expect("Client is sending message after commit to db and inserting to chain; the block is available; qed");
|
||||||
|
let block = BlockView::new(&block);
|
||||||
|
let txs = block.transactions();
|
||||||
|
// populate sender
|
||||||
|
for tx in &txs {
|
||||||
|
let _sender = tx.sender();
|
||||||
|
}
|
||||||
|
txs
|
||||||
|
}).for_each(|txs| {
|
||||||
let mut transaction_queue = self.transaction_queue.lock();
|
let mut transaction_queue = self.transaction_queue.lock();
|
||||||
let _ = self.add_transactions_to_queue(
|
let _ = self.add_transactions_to_queue(
|
||||||
chain, txs, TransactionOrigin::RetractedBlock, &mut transaction_queue
|
chain, txs, TransactionOrigin::RetractedBlock, &mut transaction_queue
|
||||||
@ -1127,24 +1121,10 @@ impl MinerService for Miner {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...and at the end remove old ones
|
// ...and at the end remove the old ones
|
||||||
{
|
{
|
||||||
let in_chain = enacted
|
|
||||||
.par_iter()
|
|
||||||
.map(|h: &H256| fetch_transactions(chain, h));
|
|
||||||
|
|
||||||
in_chain.for_each(|mut txs| {
|
|
||||||
let mut transaction_queue = self.transaction_queue.lock();
|
let mut transaction_queue = self.transaction_queue.lock();
|
||||||
|
transaction_queue.remove_old(|sender| chain.latest_nonce(sender));
|
||||||
let to_remove = txs.drain(..)
|
|
||||||
.map(|tx| {
|
|
||||||
tx.sender().expect("Transaction is in block, so sender has to be defined.")
|
|
||||||
})
|
|
||||||
.collect::<HashSet<Address>>();
|
|
||||||
for sender in to_remove {
|
|
||||||
transaction_queue.remove_all(sender, chain.latest_nonce(&sender));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if enacted.len() > 0 {
|
if enacted.len() > 0 {
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
//! 3. `remove_all` is used to inform the queue about client (state) nonce changes.
|
//! 3. `remove_all` is used to inform the queue about client (state) nonce changes.
|
||||||
//! - It removes all transactions (either from `current` or `future`) with nonce < client nonce
|
//! - It removes all transactions (either from `current` or `future`) with nonce < client nonce
|
||||||
//! - It moves matching `future` transactions to `current`
|
//! - It moves matching `future` transactions to `current`
|
||||||
|
//! 4. `remove_old` is used as convenient method to update the state nonce for all senders in the queue.
|
||||||
|
//! - Invokes `remove_all` with latest state nonce for all senders.
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@ -752,6 +754,26 @@ impl TransactionQueue {
|
|||||||
/// Removes all transactions from particular sender up to (excluding) given client (state) nonce.
|
/// Removes all transactions from particular sender up to (excluding) given client (state) nonce.
|
||||||
/// Client (State) Nonce = next valid nonce for this sender.
|
/// Client (State) Nonce = next valid nonce for this sender.
|
||||||
pub fn remove_all(&mut self, sender: Address, client_nonce: U256) {
|
pub fn remove_all(&mut self, sender: Address, client_nonce: U256) {
|
||||||
|
// Check if there is anything in current...
|
||||||
|
let should_check_in_current = self.current.by_address.row(&sender)
|
||||||
|
// If nonce == client_nonce nothing is changed
|
||||||
|
.and_then(|by_nonce| by_nonce.keys().find(|nonce| *nonce < &client_nonce))
|
||||||
|
.map(|_| ());
|
||||||
|
// ... or future
|
||||||
|
let should_check_in_future = self.future.by_address.row(&sender)
|
||||||
|
// if nonce == client_nonce we need to promote to current
|
||||||
|
.and_then(|by_nonce| by_nonce.keys().find(|nonce| *nonce <= &client_nonce))
|
||||||
|
.map(|_| ());
|
||||||
|
|
||||||
|
if should_check_in_current.or(should_check_in_future).is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.remove_all_internal(sender, client_nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always updates future and moves transactions from current to future.
|
||||||
|
fn remove_all_internal(&mut self, sender: Address, client_nonce: U256) {
|
||||||
// We will either move transaction to future or remove it completely
|
// We will either move transaction to future or remove it completely
|
||||||
// so there will be no transactions from this sender in current
|
// so there will be no transactions from this sender in current
|
||||||
self.last_nonces.remove(&sender);
|
self.last_nonces.remove(&sender);
|
||||||
@ -765,6 +787,20 @@ impl TransactionQueue {
|
|||||||
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks the current nonce for all transactions' senders in the queue and removes the old transactions.
|
||||||
|
pub fn remove_old<F>(&mut self, fetch_nonce: F) where
|
||||||
|
F: Fn(&Address) -> U256,
|
||||||
|
{
|
||||||
|
let senders = self.current.by_address.keys()
|
||||||
|
.chain(self.future.by_address.keys())
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
for sender in senders {
|
||||||
|
self.remove_all(sender, fetch_nonce(&sender));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Penalize transactions from sender of transaction with given hash.
|
/// Penalize transactions from sender of transaction with given hash.
|
||||||
/// I.e. it should change the priority of the transaction in the queue.
|
/// I.e. it should change the priority of the transaction in the queue.
|
||||||
///
|
///
|
||||||
@ -847,7 +883,7 @@ impl TransactionQueue {
|
|||||||
if order.is_some() {
|
if order.is_some() {
|
||||||
// This will keep consistency in queue
|
// This will keep consistency in queue
|
||||||
// Moves all to future and then promotes a batch from current:
|
// Moves all to future and then promotes a batch from current:
|
||||||
self.remove_all(sender, current_nonce);
|
self.remove_all_internal(sender, current_nonce);
|
||||||
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2438,7 +2474,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_reject_transactions_below_bas_gas() {
|
fn should_reject_transactions_below_base_gas() {
|
||||||
// given
|
// given
|
||||||
let mut txq = TransactionQueue::default();
|
let mut txq = TransactionQueue::default();
|
||||||
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
@ -2457,4 +2493,26 @@ mod test {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_clear_all_old_transactions() {
|
||||||
|
// given
|
||||||
|
let mut txq = TransactionQueue::default();
|
||||||
|
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
|
||||||
|
let (tx3, tx4) = new_tx_pair_default(1.into(), 0.into());
|
||||||
|
let nonce1 = tx1.nonce;
|
||||||
|
|
||||||
|
// Insert all transactions
|
||||||
|
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
|
||||||
|
assert_eq!(txq.top_transactions().len(), 4);
|
||||||
|
|
||||||
|
// when
|
||||||
|
txq.remove_old(|_| nonce1 + U256::one());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(txq.top_transactions().len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parity.js",
|
"name": "parity.js",
|
||||||
"version": "0.2.105",
|
"version": "0.2.107",
|
||||||
"main": "release/index.js",
|
"main": "release/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
"author": "Parity Team <admin@parity.io>",
|
"author": "Parity Team <admin@parity.io>",
|
||||||
@ -146,6 +146,7 @@
|
|||||||
"mobx-react-devtools": "4.2.10",
|
"mobx-react-devtools": "4.2.10",
|
||||||
"moment": "2.17.0",
|
"moment": "2.17.0",
|
||||||
"phoneformat.js": "1.0.3",
|
"phoneformat.js": "1.0.3",
|
||||||
|
"push.js": "0.0.11",
|
||||||
"qs": "6.3.0",
|
"qs": "6.3.0",
|
||||||
"react": "15.4.1",
|
"react": "15.4.1",
|
||||||
"react-ace": "4.1.0",
|
"react-ace": "4.1.0",
|
||||||
|
@ -67,7 +67,7 @@ if (window.location.hash && window.location.hash.indexOf(AUTH_HASH) === 0) {
|
|||||||
const api = new SecureApi(`ws://${parityUrl}`, token);
|
const api = new SecureApi(`ws://${parityUrl}`, token);
|
||||||
ContractInstances.create(api);
|
ContractInstances.create(api);
|
||||||
|
|
||||||
const store = initStore(api);
|
const store = initStore(api, hashHistory);
|
||||||
store.dispatch({ type: 'initAll', api });
|
store.dispatch({ type: 'initAll', api });
|
||||||
store.dispatch(setApi(api));
|
store.dispatch(setApi(api));
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
|
import { routerMiddleware } from 'react-router-redux';
|
||||||
|
|
||||||
import ErrorsMiddleware from '~/ui/Errors/middleware';
|
import ErrorsMiddleware from '~/ui/Errors/middleware';
|
||||||
import SettingsMiddleware from '~/views/Settings/middleware';
|
import SettingsMiddleware from '~/views/Settings/middleware';
|
||||||
@ -22,12 +23,13 @@ import SignerMiddleware from './providers/signerMiddleware';
|
|||||||
import statusMiddleware from '~/views/Status/middleware';
|
import statusMiddleware from '~/views/Status/middleware';
|
||||||
import CertificationsMiddleware from './providers/certifications/middleware';
|
import CertificationsMiddleware from './providers/certifications/middleware';
|
||||||
|
|
||||||
export default function (api) {
|
export default function (api, browserHistory) {
|
||||||
const errors = new ErrorsMiddleware();
|
const errors = new ErrorsMiddleware();
|
||||||
const signer = new SignerMiddleware(api);
|
const signer = new SignerMiddleware(api);
|
||||||
const settings = new SettingsMiddleware();
|
const settings = new SettingsMiddleware();
|
||||||
const status = statusMiddleware();
|
const status = statusMiddleware();
|
||||||
const certifications = new CertificationsMiddleware();
|
const certifications = new CertificationsMiddleware();
|
||||||
|
const routeMiddleware = routerMiddleware(browserHistory);
|
||||||
|
|
||||||
const middleware = [
|
const middleware = [
|
||||||
settings.toMiddleware(),
|
settings.toMiddleware(),
|
||||||
@ -36,5 +38,5 @@ export default function (api) {
|
|||||||
certifications.toMiddleware()
|
certifications.toMiddleware()
|
||||||
];
|
];
|
||||||
|
|
||||||
return middleware.concat(status, thunk);
|
return middleware.concat(status, routeMiddleware, thunk);
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,14 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { range, uniq, isEqual } from 'lodash';
|
import { range, uniq, isEqual } from 'lodash';
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
import { push } from 'react-router-redux';
|
||||||
|
|
||||||
import { hashToImageUrl } from './imagesReducer';
|
import { hashToImageUrl } from './imagesReducer';
|
||||||
import { setAddressImage } from './imagesActions';
|
import { setAddressImage } from './imagesActions';
|
||||||
|
|
||||||
import * as ABIS from '~/contracts/abi';
|
import * as ABIS from '~/contracts/abi';
|
||||||
|
import { notifyTransaction } from '~/util/notifications';
|
||||||
import imagesEthereum from '../../../assets/images/contracts/ethereum-black-64x64.png';
|
import imagesEthereum from '../../../assets/images/contracts/ethereum-black-64x64.png';
|
||||||
|
|
||||||
const ETH = {
|
const ETH = {
|
||||||
@ -28,7 +31,64 @@ const ETH = {
|
|||||||
image: imagesEthereum
|
image: imagesEthereum
|
||||||
};
|
};
|
||||||
|
|
||||||
export function setBalances (balances) {
|
function setBalances (_balances) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const accounts = state.personal.accounts;
|
||||||
|
const nextBalances = _balances;
|
||||||
|
const prevBalances = state.balances.balances;
|
||||||
|
const balances = { ...prevBalances };
|
||||||
|
|
||||||
|
Object.keys(nextBalances).forEach((address) => {
|
||||||
|
if (!balances[address]) {
|
||||||
|
balances[address] = Object.assign({}, nextBalances[address]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const balance = Object.assign({}, balances[address]);
|
||||||
|
const { tokens, txCount = balance.txCount } = nextBalances[address];
|
||||||
|
const nextTokens = [].concat(balance.tokens);
|
||||||
|
|
||||||
|
tokens.forEach((t) => {
|
||||||
|
const { token, value } = t;
|
||||||
|
const { tag } = token;
|
||||||
|
|
||||||
|
const tokenIndex = nextTokens.findIndex((tok) => tok.token.tag === tag);
|
||||||
|
|
||||||
|
if (tokenIndex === -1) {
|
||||||
|
nextTokens.push({
|
||||||
|
token,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const oldValue = nextTokens[tokenIndex].value;
|
||||||
|
|
||||||
|
// If received a token/eth (old value < new value), notify
|
||||||
|
if (oldValue.lt(value) && accounts[address]) {
|
||||||
|
const account = accounts[address];
|
||||||
|
const txValue = value.minus(oldValue);
|
||||||
|
|
||||||
|
const redirectToAccount = () => {
|
||||||
|
const route = `/account/${account.address}`;
|
||||||
|
dispatch(push(route));
|
||||||
|
};
|
||||||
|
|
||||||
|
notifyTransaction(account, token, txValue, redirectToAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTokens[tokenIndex] = { token, value };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
balances[address] = { txCount: txCount || new BigNumber(0), tokens: nextTokens };
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(_setBalances(balances));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _setBalances (balances) {
|
||||||
return {
|
return {
|
||||||
type: 'setBalances',
|
type: 'setBalances',
|
||||||
balances
|
balances
|
||||||
@ -123,14 +183,14 @@ export function fetchBalances (_addresses) {
|
|||||||
|
|
||||||
const fullFetch = addresses.length === 1;
|
const fullFetch = addresses.length === 1;
|
||||||
|
|
||||||
const fetchedAddresses = uniq(addresses.concat(Object.keys(accounts)));
|
const addressesToFetch = uniq(addresses.concat(Object.keys(accounts)));
|
||||||
|
|
||||||
return Promise
|
return Promise
|
||||||
.all(fetchedAddresses.map((addr) => fetchAccount(addr, api, fullFetch)))
|
.all(addressesToFetch.map((addr) => fetchAccount(addr, api, fullFetch)))
|
||||||
.then((accountsBalances) => {
|
.then((accountsBalances) => {
|
||||||
const balances = {};
|
const balances = {};
|
||||||
|
|
||||||
fetchedAddresses.forEach((addr, idx) => {
|
addressesToFetch.forEach((addr, idx) => {
|
||||||
balances[addr] = accountsBalances[idx];
|
balances[addr] = accountsBalances[idx];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -146,10 +206,12 @@ export function fetchBalances (_addresses) {
|
|||||||
export function updateTokensFilter (_addresses, _tokens) {
|
export function updateTokensFilter (_addresses, _tokens) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { api, balances, personal } = getState();
|
const { api, balances, personal } = getState();
|
||||||
const { visibleAccounts } = personal;
|
const { visibleAccounts, accounts } = personal;
|
||||||
const { tokensFilter } = balances;
|
const { tokensFilter } = balances;
|
||||||
|
|
||||||
const addresses = uniq(_addresses || visibleAccounts || []).sort();
|
const addressesToFetch = uniq(visibleAccounts.concat(Object.keys(accounts)));
|
||||||
|
const addresses = uniq(_addresses || addressesToFetch || []).sort();
|
||||||
|
|
||||||
const tokens = _tokens || Object.values(balances.tokens) || [];
|
const tokens = _tokens || Object.values(balances.tokens) || [];
|
||||||
const tokenAddresses = tokens.map((t) => t.address).sort();
|
const tokenAddresses = tokens.map((t) => t.address).sort();
|
||||||
|
|
||||||
@ -221,8 +283,10 @@ export function updateTokensFilter (_addresses, _tokens) {
|
|||||||
export function queryTokensFilter (tokensFilter) {
|
export function queryTokensFilter (tokensFilter) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { api, personal, balances } = getState();
|
const { api, personal, balances } = getState();
|
||||||
const { visibleAccounts } = personal;
|
const { visibleAccounts, accounts } = personal;
|
||||||
|
|
||||||
const visibleAddresses = visibleAccounts.map((a) => a.toLowerCase());
|
const visibleAddresses = visibleAccounts.map((a) => a.toLowerCase());
|
||||||
|
const addressesToFetch = uniq(visibleAddresses.concat(Object.keys(accounts)));
|
||||||
|
|
||||||
Promise
|
Promise
|
||||||
.all([
|
.all([
|
||||||
@ -237,18 +301,16 @@ export function queryTokensFilter (tokensFilter) {
|
|||||||
.concat(logsTo)
|
.concat(logsTo)
|
||||||
.forEach((log) => {
|
.forEach((log) => {
|
||||||
const tokenAddress = log.address;
|
const tokenAddress = log.address;
|
||||||
|
|
||||||
const fromAddress = '0x' + log.topics[1].slice(-40);
|
const fromAddress = '0x' + log.topics[1].slice(-40);
|
||||||
const toAddress = '0x' + log.topics[2].slice(-40);
|
const toAddress = '0x' + log.topics[2].slice(-40);
|
||||||
|
|
||||||
const fromIdx = visibleAddresses.indexOf(fromAddress);
|
if (addressesToFetch.includes(fromAddress)) {
|
||||||
const toIdx = visibleAddresses.indexOf(toAddress);
|
addresses.push(fromAddress);
|
||||||
|
|
||||||
if (fromIdx > -1) {
|
|
||||||
addresses.push(visibleAccounts[fromIdx]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toIdx > -1) {
|
if (addressesToFetch.includes(toAddress)) {
|
||||||
addresses.push(visibleAccounts[toIdx]);
|
addresses.push(toAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenAddresses.push(tokenAddress);
|
tokenAddresses.push(tokenAddress);
|
||||||
@ -269,9 +331,10 @@ export function queryTokensFilter (tokensFilter) {
|
|||||||
export function fetchTokensBalances (_addresses = null, _tokens = null) {
|
export function fetchTokensBalances (_addresses = null, _tokens = null) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { api, personal, balances } = getState();
|
const { api, personal, balances } = getState();
|
||||||
const { visibleAccounts } = personal;
|
const { visibleAccounts, accounts } = personal;
|
||||||
|
|
||||||
const addresses = _addresses || visibleAccounts;
|
const addressesToFetch = uniq(visibleAccounts.concat(Object.keys(accounts)));
|
||||||
|
const addresses = _addresses || addressesToFetch;
|
||||||
const tokens = _tokens || Object.values(balances.tokens);
|
const tokens = _tokens || Object.values(balances.tokens);
|
||||||
|
|
||||||
if (addresses.length === 0) {
|
if (addresses.length === 0) {
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { handleActions } from 'redux-actions';
|
import { handleActions } from 'redux-actions';
|
||||||
import BigNumber from 'bignumber.js';
|
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
balances: {},
|
balances: {},
|
||||||
@ -26,39 +25,7 @@ const initialState = {
|
|||||||
|
|
||||||
export default handleActions({
|
export default handleActions({
|
||||||
setBalances (state, action) {
|
setBalances (state, action) {
|
||||||
const nextBalances = action.balances;
|
const { balances } = action;
|
||||||
const prevBalances = state.balances;
|
|
||||||
const balances = { ...prevBalances };
|
|
||||||
|
|
||||||
Object.keys(nextBalances).forEach((address) => {
|
|
||||||
if (!balances[address]) {
|
|
||||||
balances[address] = Object.assign({}, nextBalances[address]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const balance = Object.assign({}, balances[address]);
|
|
||||||
const { tokens, txCount = balance.txCount } = nextBalances[address];
|
|
||||||
const nextTokens = [].concat(balance.tokens);
|
|
||||||
|
|
||||||
tokens.forEach((t) => {
|
|
||||||
const { token, value } = t;
|
|
||||||
const { tag } = token;
|
|
||||||
|
|
||||||
const tokenIndex = nextTokens.findIndex((tok) => tok.token.tag === tag);
|
|
||||||
|
|
||||||
if (tokenIndex === -1) {
|
|
||||||
nextTokens.push({
|
|
||||||
token,
|
|
||||||
value
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
nextTokens[tokenIndex] = { token, value };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
balances[address] = Object.assign({}, { txCount: txCount || new BigNumber(0), tokens: nextTokens });
|
|
||||||
});
|
|
||||||
|
|
||||||
return Object.assign({}, state, { balances });
|
return Object.assign({}, state, { balances });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -21,11 +21,11 @@ export Status from './status';
|
|||||||
|
|
||||||
export apiReducer from './apiReducer';
|
export apiReducer from './apiReducer';
|
||||||
export balancesReducer from './balancesReducer';
|
export balancesReducer from './balancesReducer';
|
||||||
|
export blockchainReducer from './blockchainReducer';
|
||||||
|
export compilerReducer from './compilerReducer';
|
||||||
export imagesReducer from './imagesReducer';
|
export imagesReducer from './imagesReducer';
|
||||||
export personalReducer from './personalReducer';
|
export personalReducer from './personalReducer';
|
||||||
export signerReducer from './signerReducer';
|
export signerReducer from './signerReducer';
|
||||||
export statusReducer from './statusReducer';
|
|
||||||
export blockchainReducer from './blockchainReducer';
|
|
||||||
export compilerReducer from './compilerReducer';
|
|
||||||
export snackbarReducer from './snackbarReducer';
|
export snackbarReducer from './snackbarReducer';
|
||||||
|
export statusReducer from './statusReducer';
|
||||||
export walletReducer from './walletReducer';
|
export walletReducer from './walletReducer';
|
||||||
|
@ -54,7 +54,10 @@ export default class Status {
|
|||||||
this._api.eth
|
this._api.eth
|
||||||
.getBlockByNumber(blockNumber)
|
.getBlockByNumber(blockNumber)
|
||||||
.then((block) => {
|
.then((block) => {
|
||||||
this._store.dispatch(statusCollection({ gasLimit: block.gasLimit }));
|
this._store.dispatch(statusCollection({
|
||||||
|
blockTimestamp: block.timestamp,
|
||||||
|
gasLimit: block.gasLimit
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.warn('status._subscribeBlockNumber', 'getBlockByNumber', error);
|
console.warn('status._subscribeBlockNumber', 'getBlockByNumber', error);
|
||||||
|
@ -19,6 +19,7 @@ import { handleActions } from 'redux-actions';
|
|||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
blockNumber: new BigNumber(0),
|
blockNumber: new BigNumber(0),
|
||||||
|
blockTimestamp: new Date(),
|
||||||
devLogs: [],
|
devLogs: [],
|
||||||
devLogsLevels: null,
|
devLogsLevels: null,
|
||||||
devLogsEnabled: false,
|
devLogsEnabled: false,
|
||||||
|
@ -17,7 +17,12 @@
|
|||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
import { routerReducer } from 'react-router-redux';
|
import { routerReducer } from 'react-router-redux';
|
||||||
|
|
||||||
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer, walletReducer } from './providers';
|
import {
|
||||||
|
apiReducer, balancesReducer, blockchainReducer,
|
||||||
|
compilerReducer, imagesReducer, personalReducer,
|
||||||
|
signerReducer, statusReducer as nodeStatusReducer,
|
||||||
|
snackbarReducer, walletReducer
|
||||||
|
} from './providers';
|
||||||
import certificationsReducer from './providers/certifications/reducer';
|
import certificationsReducer from './providers/certifications/reducer';
|
||||||
|
|
||||||
import errorReducer from '~/ui/Errors/reducers';
|
import errorReducer from '~/ui/Errors/reducers';
|
||||||
|
@ -32,9 +32,9 @@ const storeCreation = window.devToolsExtension
|
|||||||
? window.devToolsExtension()(createStore)
|
? window.devToolsExtension()(createStore)
|
||||||
: createStore;
|
: createStore;
|
||||||
|
|
||||||
export default function (api) {
|
export default function (api, browserHistory) {
|
||||||
const reducers = initReducers();
|
const reducers = initReducers();
|
||||||
const middleware = initMiddleware(api);
|
const middleware = initMiddleware(api, browserHistory);
|
||||||
const store = applyMiddleware(...middleware)(storeCreation)(reducers);
|
const store = applyMiddleware(...middleware)(storeCreation)(reducers);
|
||||||
|
|
||||||
new BalancesProvider(store, api).start();
|
new BalancesProvider(store, api).start();
|
||||||
|
@ -17,11 +17,13 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
||||||
|
|
||||||
|
import { nodeOrStringProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
import styles from './actionbar.css';
|
import styles from './actionbar.css';
|
||||||
|
|
||||||
export default class Actionbar extends Component {
|
export default class Actionbar extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
title: PropTypes.string,
|
title: nodeOrStringProptype(),
|
||||||
buttons: PropTypes.array,
|
buttons: PropTypes.array,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
className: PropTypes.string
|
className: PropTypes.string
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
.layout {
|
.layout {
|
||||||
padding: 0.25em 0.25em 1em 0.25em;
|
padding: 0.25em 0.25em 1em 0.25em;
|
||||||
|
|
||||||
> * {
|
&>div {
|
||||||
margin-bottom: 0.75em;
|
margin-bottom: 0.75em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,22 +16,39 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
|
import Actionbar from '../Actionbar';
|
||||||
|
import { nodeOrStringProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
import styles from './page.css';
|
import styles from './page.css';
|
||||||
|
|
||||||
export default class Page extends Component {
|
export default class Page extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
buttons: PropTypes.array,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
children: PropTypes.node
|
children: PropTypes.node,
|
||||||
|
title: nodeOrStringProptype()
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { className, children } = this.props;
|
const { buttons, className, children, title } = this.props;
|
||||||
const classes = `${styles.layout} ${className}`;
|
const classes = `${styles.layout} ${className}`;
|
||||||
|
let actionbar = null;
|
||||||
|
|
||||||
|
if (title || buttons) {
|
||||||
|
actionbar = (
|
||||||
|
<Actionbar
|
||||||
|
buttons={ buttons }
|
||||||
|
title={ title } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
|
{ actionbar }
|
||||||
<div className={ classes }>
|
<div className={ classes }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
45
js/src/util/notifications.js
Normal file
45
js/src/util/notifications.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import Push from 'push.js';
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
import { noop } from 'lodash';
|
||||||
|
|
||||||
|
import { fromWei } from '~/api/util/wei';
|
||||||
|
|
||||||
|
import ethereumIcon from '~/../assets/images/contracts/ethereum-black-64x64.png';
|
||||||
|
import unkownIcon from '~/../assets/images/contracts/unknown-64x64.png';
|
||||||
|
|
||||||
|
export function notifyTransaction (account, token, _value, onClick) {
|
||||||
|
const name = account.name || account.address;
|
||||||
|
const value = token.tag.toLowerCase() === 'eth'
|
||||||
|
? fromWei(_value)
|
||||||
|
: _value.div(new BigNumber(token.format || 1));
|
||||||
|
|
||||||
|
const icon = token.tag.toLowerCase() === 'eth'
|
||||||
|
? ethereumIcon
|
||||||
|
: (token.image || unkownIcon);
|
||||||
|
|
||||||
|
Push.create(`${name}`, {
|
||||||
|
body: `You just received ${value.toFormat()} ${token.tag.toUpperCase()}`,
|
||||||
|
icon: {
|
||||||
|
x16: icon,
|
||||||
|
x32: icon
|
||||||
|
},
|
||||||
|
timeout: 20000,
|
||||||
|
onClick: onClick || noop
|
||||||
|
});
|
||||||
|
}
|
@ -51,9 +51,16 @@ export default class Dapp extends Component {
|
|||||||
src = `${dappsUrl}/${app.contentHash}/`;
|
src = `${dappsUrl}/${app.contentHash}/`;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
const dapphost = process.env.NODE_ENV === 'production' && !app.secure
|
let dapphost = process.env.DAPPS_URL || (
|
||||||
|
process.env.NODE_ENV === 'production' && !app.secure
|
||||||
? `${dappsUrl}/ui`
|
? `${dappsUrl}/ui`
|
||||||
: '';
|
: ''
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dapphost === '/') {
|
||||||
|
dapphost = '';
|
||||||
|
}
|
||||||
|
|
||||||
src = `${dapphost}/${app.url}.html`;
|
src = `${dapphost}/${app.url}.html`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ export default class Signer extends Component {
|
|||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Actionbar
|
<Actionbar title='Trusted Signer' />
|
||||||
title='Trusted Signer' />
|
|
||||||
<RequestsPage />
|
<RequestsPage />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -30,12 +30,6 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action unsubscribe () {
|
|
||||||
if (this._timeoutId) {
|
|
||||||
clearTimeout(this._timeoutId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action setBalance = (address, balance) => {
|
@action setBalance = (address, balance) => {
|
||||||
this.setBalances({ [address]: balance });
|
this.setBalances({ [address]: balance });
|
||||||
}
|
}
|
||||||
@ -50,6 +44,12 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action unsubscribe () {
|
||||||
|
if (this._timeoutId) {
|
||||||
|
clearTimeout(this._timeoutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fetchBalance (address) {
|
fetchBalance (address) {
|
||||||
this._api.eth
|
this._api.eth
|
||||||
.getBalance(address)
|
.getBalance(address)
|
||||||
|
@ -22,7 +22,7 @@ import ReorderIcon from 'material-ui/svg-icons/action/reorder';
|
|||||||
|
|
||||||
import { Container } from '~/ui';
|
import { Container } from '~/ui';
|
||||||
|
|
||||||
import styles from './Debug.css';
|
import styles from './debug.css';
|
||||||
|
|
||||||
export default class Debug extends Component {
|
export default class Debug extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './Debug';
|
export default from './debug';
|
||||||
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './MiningSettings';
|
export default from './miningSettings';
|
||||||
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './Status';
|
export default from './status';
|
||||||
|
@ -28,10 +28,19 @@
|
|||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
.blockinfo {
|
.blockInfo {
|
||||||
font-size: 24px;
|
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
line-height: 24px;
|
font-size: 1.5em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blockByline {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.padBottom {
|
||||||
|
padding-bottom: 1.25em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.col,
|
.col,
|
@ -14,14 +14,16 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
|
||||||
import bytes from 'bytes';
|
import bytes from 'bytes';
|
||||||
|
import moment from 'moment';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import { Container, ContainerTitle, Input } from '~/ui';
|
import { Container, ContainerTitle, Input } from '~/ui';
|
||||||
|
|
||||||
import styles from './Status.css';
|
|
||||||
import MiningSettings from '../MiningSettings';
|
import MiningSettings from '../MiningSettings';
|
||||||
|
|
||||||
|
import styles from './status.css';
|
||||||
|
|
||||||
export default class Status extends Component {
|
export default class Status extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
nodeStatus: PropTypes.object.isRequired,
|
nodeStatus: PropTypes.object.isRequired,
|
||||||
@ -44,23 +46,26 @@ export default class Status extends Component {
|
|||||||
<div className={ styles.container }>
|
<div className={ styles.container }>
|
||||||
<div className={ styles.row }>
|
<div className={ styles.row }>
|
||||||
<div className={ styles.col3 }>
|
<div className={ styles.col3 }>
|
||||||
<div className={ styles.col12 }>
|
<div className={ `${styles.col12} ${styles.padBottom}` }>
|
||||||
<ContainerTitle title='best block' />
|
<ContainerTitle title='best block' />
|
||||||
<h2 { ...this._test('best-block') } className={ styles.blockinfo }>
|
<div { ...this._test('best-block') } className={ styles.blockInfo }>
|
||||||
#{ nodeStatus.blockNumber.toFormat() }
|
#{ nodeStatus.blockNumber.toFormat() }
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col12 }>
|
<div className={ styles.blockByline }>
|
||||||
|
{ moment().calendar(nodeStatus.blockTimestamp) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={ `${styles.col12} ${styles.padBottom}` }>
|
||||||
<ContainerTitle title='peers' />
|
<ContainerTitle title='peers' />
|
||||||
<h2 { ...this._test('peers') } className={ styles.blockinfo }>
|
<div { ...this._test('peers') } className={ styles.blockInfo }>
|
||||||
{ peers }
|
{ peers }
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col12 }>
|
</div>
|
||||||
|
<div className={ `${styles.col12} ${styles.padBottom}` }>
|
||||||
<ContainerTitle title='hash rate' />
|
<ContainerTitle title='hash rate' />
|
||||||
<h2 { ...this._test('hashrate') } className={ styles.blockinfo }>
|
<div { ...this._test('hashrate') } className={ styles.blockInfo }>
|
||||||
{ `${hashrate} H/s` }
|
{ `${hashrate} H/s` }
|
||||||
</h2>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.col5 }>
|
<div className={ styles.col5 }>
|
@ -14,4 +14,4 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export default from './StatusPage';
|
export default from './statusPage';
|
||||||
|
@ -14,5 +14,9 @@
|
|||||||
/* You should have received a copy of the GNU General Public License
|
/* You should have received a copy of the GNU General Public License
|
||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
.container {
|
|
||||||
|
.body {
|
||||||
|
&>div {
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,6 +23,8 @@ import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from '~/redux/
|
|||||||
import Debug from '../../components/Debug';
|
import Debug from '../../components/Debug';
|
||||||
import Status from '../../components/Status';
|
import Status from '../../components/Status';
|
||||||
|
|
||||||
|
import styles from './statusPage.css';
|
||||||
|
|
||||||
class StatusPage extends Component {
|
class StatusPage extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
nodeStatus: PropTypes.object.isRequired,
|
nodeStatus: PropTypes.object.isRequired,
|
||||||
@ -39,7 +41,7 @@ class StatusPage extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={ styles.body }>
|
||||||
<Status { ...this.props } />
|
<Status { ...this.props } />
|
||||||
<Debug { ...this.props } />
|
<Debug { ...this.props } />
|
||||||
</div>
|
</div>
|
@ -16,22 +16,16 @@
|
|||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { Actionbar, Page } from '~/ui';
|
import { Page } from '~/ui';
|
||||||
|
|
||||||
import StatusPage from './containers/StatusPage';
|
import StatusPage from './containers/StatusPage';
|
||||||
|
|
||||||
import styles from './status.css';
|
|
||||||
|
|
||||||
export default class Status extends Component {
|
export default class Status extends Component {
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className={ styles.container }>
|
<Page title='status'>
|
||||||
<Actionbar
|
|
||||||
title='status' />
|
|
||||||
<Page>
|
|
||||||
<StatusPage />
|
<StatusPage />
|
||||||
</Page>
|
</Page>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ const path = require('path');
|
|||||||
const WebpackErrorNotificationPlugin = require('webpack-error-notification');
|
const WebpackErrorNotificationPlugin = require('webpack-error-notification');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
|
||||||
const Shared = require('./shared');
|
const Shared = require('./shared');
|
||||||
const DAPPS = require('../src/dapps');
|
const DAPPS = require('../src/dapps');
|
||||||
@ -41,7 +42,7 @@ module.exports = {
|
|||||||
output: {
|
output: {
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
path: path.join(__dirname, '../', DEST),
|
path: path.join(__dirname, '../', DEST),
|
||||||
filename: '[name].[hash].js'
|
filename: '[name].[hash:10].js'
|
||||||
},
|
},
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
@ -85,13 +86,20 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
include: [ /src/ ],
|
include: [ /src/ ],
|
||||||
|
// exclude: [ /src\/dapps/ ],
|
||||||
|
loader: isProd ? ExtractTextPlugin.extract([
|
||||||
|
// 'style-loader',
|
||||||
|
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
|
||||||
|
'postcss-loader'
|
||||||
|
]) : undefined,
|
||||||
// use: [ 'happypack/loader?id=css' ]
|
// use: [ 'happypack/loader?id=css' ]
|
||||||
use: [
|
use: isProd ? undefined : [
|
||||||
'style-loader',
|
'style-loader',
|
||||||
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
|
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
|
||||||
'postcss-loader'
|
'postcss-loader'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
exclude: [ /src/ ],
|
exclude: [ /src/ ],
|
||||||
@ -99,11 +107,15 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpg)$/,
|
test: /\.(png|jpg)$/,
|
||||||
use: [ 'file-loader?name=[name].[hash].[ext]' ]
|
use: [ 'file-loader?&name=assets/[name].[hash:10].[ext]' ]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(woff(2)|ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
test: /\.(woff(2)|ttf|eot|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
use: [ 'file-loader' ]
|
use: [ 'file-loader?name=fonts/[name][hash:10].[ext]' ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.svg(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
use: [ 'file-loader?name=assets/[name].[hash:10].[ext]' ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
noParse: [
|
noParse: [
|
||||||
@ -153,13 +165,20 @@ module.exports = {
|
|||||||
if (!isProd) {
|
if (!isProd) {
|
||||||
plugins.push(
|
plugins.push(
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
filename: 'commons.[hash].js',
|
filename: 'commons.[hash:10].js',
|
||||||
name: 'commons',
|
name: 'commons',
|
||||||
minChunks: Infinity
|
minChunks: Infinity
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isProd) {
|
||||||
|
plugins.push(new ExtractTextPlugin({
|
||||||
|
filename: 'styles/[name].[hash:10].css',
|
||||||
|
allChunks: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}())
|
}())
|
||||||
};
|
};
|
||||||
|
@ -89,11 +89,13 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
|
|||||||
signer.peek(&id).map(|confirmation| {
|
signer.peek(&id).map(|confirmation| {
|
||||||
let mut payload = confirmation.payload.clone();
|
let mut payload = confirmation.payload.clone();
|
||||||
// Modify payload
|
// Modify payload
|
||||||
match (&mut payload, modification.gas_price) {
|
if let ConfirmationPayload::SendTransaction(ref mut request) = payload {
|
||||||
(&mut ConfirmationPayload::SendTransaction(ref mut request), Some(gas_price)) => {
|
if let Some(gas_price) = modification.gas_price {
|
||||||
request.gas_price = gas_price.into();
|
request.gas_price = gas_price.into();
|
||||||
},
|
}
|
||||||
_ => {},
|
if let Some(gas) = modification.gas {
|
||||||
|
request.gas = gas.into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Execute
|
// Execute
|
||||||
let result = dispatch::execute(&*client, &*miner, &*accounts, payload, Some(pass));
|
let result = dispatch::execute(&*client, &*miner, &*accounts, payload, Some(pass));
|
||||||
|
@ -183,7 +183,7 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
let t = Transaction {
|
let t = Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(0x50505),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![]
|
data: vec![]
|
||||||
@ -198,7 +198,7 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
let request = r#"{
|
let request = r#"{
|
||||||
"jsonrpc":"2.0",
|
"jsonrpc":"2.0",
|
||||||
"method":"signer_confirmRequest",
|
"method":"signer_confirmRequest",
|
||||||
"params":["0x1", {"gasPrice":"0x1000"}, "test"],
|
"params":["0x1", {"gasPrice":"0x1000","gas":"0x50505"}, "test"],
|
||||||
"id":1
|
"id":1
|
||||||
}"#;
|
}"#;
|
||||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||||
|
@ -142,6 +142,8 @@ pub struct TransactionModification {
|
|||||||
/// Modified gas price
|
/// Modified gas price
|
||||||
#[serde(rename="gasPrice")]
|
#[serde(rename="gasPrice")]
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
/// Modified gas
|
||||||
|
pub gas: Option<U256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents two possible return values.
|
/// Represents two possible return values.
|
||||||
@ -275,18 +277,26 @@ mod tests {
|
|||||||
let s1 = r#"{
|
let s1 = r#"{
|
||||||
"gasPrice":"0xba43b7400"
|
"gasPrice":"0xba43b7400"
|
||||||
}"#;
|
}"#;
|
||||||
let s2 = r#"{}"#;
|
let s2 = r#"{"gas": "0x1233"}"#;
|
||||||
|
let s3 = r#"{}"#;
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res1: TransactionModification = serde_json::from_str(s1).unwrap();
|
let res1: TransactionModification = serde_json::from_str(s1).unwrap();
|
||||||
let res2: TransactionModification = serde_json::from_str(s2).unwrap();
|
let res2: TransactionModification = serde_json::from_str(s2).unwrap();
|
||||||
|
let res3: TransactionModification = serde_json::from_str(s3).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(res1, TransactionModification {
|
assert_eq!(res1, TransactionModification {
|
||||||
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
||||||
|
gas: None,
|
||||||
});
|
});
|
||||||
assert_eq!(res2, TransactionModification {
|
assert_eq!(res2, TransactionModification {
|
||||||
gas_price: None,
|
gas_price: None,
|
||||||
|
gas: Some(U256::from_str("1233").unwrap()),
|
||||||
|
});
|
||||||
|
assert_eq!(res3, TransactionModification {
|
||||||
|
gas_price: None,
|
||||||
|
gas: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1678,7 +1678,7 @@ impl ChainSync {
|
|||||||
|
|
||||||
pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) {
|
pub fn on_packet(&mut self, io: &mut SyncIo, peer: PeerId, packet_id: u8, data: &[u8]) {
|
||||||
if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) {
|
if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) {
|
||||||
debug!(target:"sync", "Unexpected packet from unregistered peer: {}:{}", peer, io.peer_info(peer));
|
debug!(target:"sync", "Unexpected packet {} from unregistered peer: {}:{}", packet_id, peer, io.peer_info(peer));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let rlp = UntrustedRlp::new(data);
|
let rlp = UntrustedRlp::new(data);
|
||||||
|
@ -131,6 +131,10 @@ impl<'s, 'h> SyncIo for NetSyncIo<'s, 'h> {
|
|||||||
fn protocol_version(&self, protocol: &ProtocolId, peer_id: PeerId) -> u8 {
|
fn protocol_version(&self, protocol: &ProtocolId, peer_id: PeerId) -> u8 {
|
||||||
self.network.protocol_version(*protocol, peer_id).unwrap_or(0)
|
self.network.protocol_version(*protocol, peer_id).unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peer_info(&self, peer_id: PeerId) -> String {
|
||||||
|
self.network.peer_client_version(peer_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
|||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write, ErrorKind};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use ethkey::{KeyPair, Secret, Random, Generator};
|
use ethkey::{KeyPair, Secret, Random, Generator};
|
||||||
use mio::*;
|
use mio::*;
|
||||||
@ -381,8 +381,6 @@ pub struct Host {
|
|||||||
impl Host {
|
impl Host {
|
||||||
/// Create a new instance
|
/// Create a new instance
|
||||||
pub fn new(mut config: NetworkConfiguration, stats: Arc<NetworkStats>) -> Result<Host, NetworkError> {
|
pub fn new(mut config: NetworkConfiguration, stats: Arc<NetworkStats>) -> Result<Host, NetworkError> {
|
||||||
trace!(target: "host", "Creating new Host object");
|
|
||||||
|
|
||||||
let mut listen_address = match config.listen_address {
|
let mut listen_address = match config.listen_address {
|
||||||
None => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), DEFAULT_PORT)),
|
None => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), DEFAULT_PORT)),
|
||||||
Some(addr) => addr,
|
Some(addr) => addr,
|
||||||
@ -405,6 +403,7 @@ impl Host {
|
|||||||
// Setup the server socket
|
// Setup the server socket
|
||||||
let tcp_listener = try!(TcpListener::bind(&listen_address));
|
let tcp_listener = try!(TcpListener::bind(&listen_address));
|
||||||
listen_address = SocketAddr::new(listen_address.ip(), try!(tcp_listener.local_addr()).port());
|
listen_address = SocketAddr::new(listen_address.ip(), try!(tcp_listener.local_addr()).port());
|
||||||
|
debug!(target: "network", "Listening at {:?}", listen_address);
|
||||||
let udp_port = config.udp_port.unwrap_or(listen_address.port());
|
let udp_port = config.udp_port.unwrap_or(listen_address.port());
|
||||||
let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port };
|
let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port };
|
||||||
|
|
||||||
@ -707,7 +706,10 @@ impl Host {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
match TcpStream::connect(&address) {
|
match TcpStream::connect(&address) {
|
||||||
Ok(socket) => socket,
|
Ok(socket) => {
|
||||||
|
trace!(target: "network", "Connecting to {:?}", address);
|
||||||
|
socket
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "network", "Can't connect to address {:?}: {:?}", address, e);
|
debug!(target: "network", "Can't connect to address {:?}: {:?}", address, e);
|
||||||
return;
|
return;
|
||||||
@ -749,7 +751,9 @@ impl Host {
|
|||||||
let socket = match self.tcp_listener.lock().accept() {
|
let socket = match self.tcp_listener.lock().accept() {
|
||||||
Ok((sock, _addr)) => sock,
|
Ok((sock, _addr)) => sock,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
if e.kind() != ErrorKind::WouldBlock {
|
||||||
debug!(target: "network", "Error accepting connection: {:?}", e);
|
debug!(target: "network", "Error accepting connection: {:?}", e);
|
||||||
|
}
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -435,16 +435,16 @@ impl Session {
|
|||||||
|
|
||||||
// map to protocol
|
// map to protocol
|
||||||
let protocol = self.info.capabilities[i].protocol;
|
let protocol = self.info.capabilities[i].protocol;
|
||||||
let pid = packet_id - self.info.capabilities[i].id_offset;
|
let protocol_packet_id = packet_id - self.info.capabilities[i].id_offset;
|
||||||
|
|
||||||
match *self.protocol_states.entry(protocol).or_insert_with(|| ProtocolState::Pending(Vec::new())) {
|
match *self.protocol_states.entry(protocol).or_insert_with(|| ProtocolState::Pending(Vec::new())) {
|
||||||
ProtocolState::Connected => {
|
ProtocolState::Connected => {
|
||||||
trace!(target: "network", "Packet {} mapped to {:?}:{}, i={}, capabilities={:?}", packet_id, protocol, pid, i, self.info.capabilities);
|
trace!(target: "network", "Packet {} mapped to {:?}:{}, i={}, capabilities={:?}", packet_id, protocol, protocol_packet_id, i, self.info.capabilities);
|
||||||
Ok(SessionData::Packet { data: packet.data, protocol: protocol, packet_id: pid } )
|
Ok(SessionData::Packet { data: packet.data, protocol: protocol, packet_id: protocol_packet_id } )
|
||||||
}
|
}
|
||||||
ProtocolState::Pending(ref mut pending) => {
|
ProtocolState::Pending(ref mut pending) => {
|
||||||
trace!(target: "network", "Packet {} deferred until protocol connection event completion", packet_id);
|
trace!(target: "network", "Packet {} deferred until protocol connection event completion", packet_id);
|
||||||
pending.push((packet.data, packet_id));
|
pending.push((packet.data, protocol_packet_id));
|
||||||
|
|
||||||
Ok(SessionData::Continue)
|
Ok(SessionData::Continue)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::collections::hash_map::Keys;
|
||||||
|
|
||||||
/// Structure to hold double-indexed values
|
/// Structure to hold double-indexed values
|
||||||
///
|
///
|
||||||
@ -41,6 +42,11 @@ impl<Row, Col, Val> Table<Row, Col, Val>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns keys iterator for this Table.
|
||||||
|
pub fn keys(&self) -> Keys<Row, HashMap<Col, Val>> {
|
||||||
|
self.map.keys()
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes all elements from this Table
|
/// Removes all elements from this Table
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.map.clear();
|
self.map.clear();
|
||||||
|
Loading…
Reference in New Issue
Block a user