Merge branch 'master' into ui-2
This commit is contained in:
commit
2ffb6496f4
@ -46,7 +46,7 @@ pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address,
|
|||||||
From::from(stream.as_raw().sha3())
|
From::from(stream.as_raw().sha3())
|
||||||
},
|
},
|
||||||
CreateContractAddress::FromCodeHash => {
|
CreateContractAddress::FromCodeHash => {
|
||||||
let mut buffer = [0u8; 20 + 32];
|
let mut buffer = [0xffu8; 20 + 32];
|
||||||
&mut buffer[20..].copy_from_slice(&code_hash[..]);
|
&mut buffer[20..].copy_from_slice(&code_hash[..]);
|
||||||
From::from((&buffer[..]).sha3())
|
From::from((&buffer[..]).sha3())
|
||||||
},
|
},
|
||||||
|
@ -127,7 +127,7 @@ impl From<ethjson::state::Transaction> for SignedTransaction {
|
|||||||
};
|
};
|
||||||
match secret {
|
match secret {
|
||||||
Some(s) => tx.sign(&s, None),
|
Some(s) => tx.sign(&s, None),
|
||||||
None => tx.null_sign(),
|
None => tx.null_sign(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,13 +210,13 @@ impl Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add EIP-86 compatible empty signature.
|
/// Add EIP-86 compatible empty signature.
|
||||||
pub fn null_sign(self) -> SignedTransaction {
|
pub fn null_sign(self, network_id: u64) -> SignedTransaction {
|
||||||
SignedTransaction {
|
SignedTransaction {
|
||||||
transaction: UnverifiedTransaction {
|
transaction: UnverifiedTransaction {
|
||||||
unsigned: self,
|
unsigned: self,
|
||||||
r: U256::zero(),
|
r: U256::zero(),
|
||||||
s: U256::zero(),
|
s: U256::zero(),
|
||||||
v: 0,
|
v: network_id,
|
||||||
hash: 0.into(),
|
hash: 0.into(),
|
||||||
}.compute_hash(),
|
}.compute_hash(),
|
||||||
sender: UNSIGNED_SENDER,
|
sender: UNSIGNED_SENDER,
|
||||||
|
@ -14,8 +14,6 @@
|
|||||||
// 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 BalancesProvider from './balances';
|
|
||||||
import { showSnackbar } from './snackbarActions';
|
|
||||||
import { DEFAULT_NETCHAIN } from './statusReducer';
|
import { DEFAULT_NETCHAIN } from './statusReducer';
|
||||||
|
|
||||||
export default class ChainMiddleware {
|
export default class ChainMiddleware {
|
||||||
@ -24,20 +22,34 @@ export default class ChainMiddleware {
|
|||||||
if (action.type === 'statusCollection') {
|
if (action.type === 'statusCollection') {
|
||||||
const { collection } = action;
|
const { collection } = action;
|
||||||
|
|
||||||
if (collection && collection.netChain) {
|
if (collection) {
|
||||||
const newChain = collection.netChain;
|
|
||||||
const { nodeStatus } = store.getState();
|
const { nodeStatus } = store.getState();
|
||||||
|
const { netChain, nodeKind } = nodeStatus;
|
||||||
|
const newChain = collection.netChain;
|
||||||
|
const newNodeKind = collection.nodeKind;
|
||||||
|
let reloadChain = false;
|
||||||
|
let reloadType = false;
|
||||||
|
|
||||||
if (newChain !== nodeStatus.netChain && nodeStatus.netChain !== DEFAULT_NETCHAIN) {
|
// force reload when chain has changed and is not initial value
|
||||||
store.dispatch(showSnackbar(`Switched to ${newChain}. The UI will reload now...`));
|
if (newChain) {
|
||||||
|
const hasChainChanged = newChain !== netChain;
|
||||||
|
const isInitialChain = netChain === DEFAULT_NETCHAIN;
|
||||||
|
|
||||||
|
reloadChain = !isInitialChain && hasChainChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
// force reload when nodeKind (availability or capability) has changed
|
||||||
|
if (newNodeKind && nodeKind) {
|
||||||
|
const hasAvailabilityChanged = nodeKind.availability !== newNodeKind.availability;
|
||||||
|
const hasCapabilityChanged = nodeKind.capability !== newNodeKind.capability;
|
||||||
|
|
||||||
|
reloadType = hasAvailabilityChanged || hasCapabilityChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reloadChain || reloadType) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Fetch the new balances without notifying the user of any change
|
|
||||||
BalancesProvider.get(store).fetchAllBalances({
|
|
||||||
changedNetwork: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,22 @@ import { createWsApi } from '~/../test/e2e/ethapi';
|
|||||||
let middleware;
|
let middleware;
|
||||||
let next;
|
let next;
|
||||||
let store;
|
let store;
|
||||||
|
let clock;
|
||||||
|
|
||||||
const api = createWsApi();
|
const api = createWsApi();
|
||||||
|
|
||||||
Contracts.create(api);
|
Contracts.create(api);
|
||||||
|
|
||||||
|
function stubGlobals () {
|
||||||
|
clock = sinon.useFakeTimers();
|
||||||
|
sinon.spy(window.location, 'reload');
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreGlobals () {
|
||||||
|
window.location.reload.restore();
|
||||||
|
clock.restore();
|
||||||
|
}
|
||||||
|
|
||||||
function createMiddleware (collection = {}) {
|
function createMiddleware (collection = {}) {
|
||||||
middleware = new ChainMiddleware().toMiddleware();
|
middleware = new ChainMiddleware().toMiddleware();
|
||||||
next = sinon.stub();
|
next = sinon.stub();
|
||||||
@ -46,10 +57,22 @@ function createMiddleware (collection = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function callMiddleware (action) {
|
function callMiddleware (action) {
|
||||||
return middleware(store)(next)(action);
|
const result = middleware(store)(next)(action);
|
||||||
|
|
||||||
|
clock.tick(100);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('reduxs/providers/ChainMiddleware', () => {
|
describe('reduxs/providers/ChainMiddleware', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
stubGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
restoreGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
describe('next action', () => {
|
describe('next action', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
createMiddleware();
|
createMiddleware();
|
||||||
@ -69,25 +92,25 @@ describe('reduxs/providers/ChainMiddleware', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('chain switching', () => {
|
describe('chain switching', () => {
|
||||||
it('does not dispatch when moving from the initial/unknown chain', () => {
|
it('does not reload when moving from the initial/unknown chain', () => {
|
||||||
createMiddleware();
|
createMiddleware();
|
||||||
callMiddleware({ type: 'statusCollection', collection: { netChain: 'homestead' } });
|
callMiddleware({ type: 'statusCollection', collection: { netChain: 'homestead' } });
|
||||||
|
|
||||||
expect(store.dispatch).not.to.have.been.called;
|
expect(window.location.reload).not.to.have.been.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not dispatch when moving to the same chain', () => {
|
it('does not reload when moving to the same chain', () => {
|
||||||
createMiddleware({ netChain: 'homestead' });
|
createMiddleware({ netChain: 'homestead' });
|
||||||
callMiddleware({ type: 'statusCollection', collection: { netChain: 'homestead' } });
|
callMiddleware({ type: 'statusCollection', collection: { netChain: 'homestead' } });
|
||||||
|
|
||||||
expect(store.dispatch).not.to.have.been.called;
|
expect(window.location.reload).not.to.have.been.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does dispatch when moving between chains', () => {
|
it('does reload when moving between chains', () => {
|
||||||
createMiddleware({ netChain: 'homestead' });
|
createMiddleware({ netChain: 'homestead' });
|
||||||
callMiddleware({ type: 'statusCollection', collection: { netChain: 'ropsten' } });
|
callMiddleware({ type: 'statusCollection', collection: { netChain: 'ropsten' } });
|
||||||
|
|
||||||
expect(store.dispatch).to.have.been.called;
|
expect(window.location.reload).to.have.been.called;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -156,7 +156,8 @@ export default class Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pollTraceMode = () => {
|
_pollTraceMode = () => {
|
||||||
return this._api.trace.block()
|
return this._api.trace
|
||||||
|
.block()
|
||||||
.then(blockTraces => {
|
.then(blockTraces => {
|
||||||
// Assumes not in Trace Mode if no transactions
|
// Assumes not in Trace Mode if no transactions
|
||||||
// in latest block...
|
// in latest block...
|
||||||
@ -168,14 +169,12 @@ export default class Status {
|
|||||||
getApiStatus = () => {
|
getApiStatus = () => {
|
||||||
const { isConnected, isConnecting, needsToken, secureToken } = this._api;
|
const { isConnected, isConnecting, needsToken, secureToken } = this._api;
|
||||||
|
|
||||||
const apiStatus = {
|
return {
|
||||||
isConnected,
|
isConnected,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
needsToken,
|
needsToken,
|
||||||
secureToken
|
secureToken
|
||||||
};
|
};
|
||||||
|
|
||||||
return apiStatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_pollStatus = () => {
|
_pollStatus = () => {
|
||||||
@ -194,7 +193,10 @@ export default class Status {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusPromises = [ this._api.eth.syncing(), this._api.parity.netPeers() ];
|
const statusPromises = [
|
||||||
|
this._api.eth.syncing(),
|
||||||
|
this._api.parity.netPeers()
|
||||||
|
];
|
||||||
|
|
||||||
return Promise
|
return Promise
|
||||||
.all(statusPromises)
|
.all(statusPromises)
|
||||||
@ -225,7 +227,10 @@ export default class Status {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextTimeout = (timeout = 30000) => {
|
const { nodeKindFull } = this._store.getState().nodeStatus;
|
||||||
|
const defaultTimeout = (nodeKindFull === false ? 240 : 30) * 1000;
|
||||||
|
|
||||||
|
const nextTimeout = (timeout = defaultTimeout) => {
|
||||||
if (this._timeoutIds.longStatus) {
|
if (this._timeoutIds.longStatus) {
|
||||||
clearTimeout(this._timeoutIds.longStatus);
|
clearTimeout(this._timeoutIds.longStatus);
|
||||||
}
|
}
|
||||||
@ -233,24 +238,34 @@ export default class Status {
|
|||||||
this._timeoutIds.longStatus = setTimeout(() => this._pollLongStatus(), timeout);
|
this._timeoutIds.longStatus = setTimeout(() => this._pollLongStatus(), timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise
|
const statusPromises = [
|
||||||
.all([
|
this._api.parity.nodeKind(),
|
||||||
this._api.parity.netPeers(),
|
this._api.parity.netPeers(),
|
||||||
this._api.web3.clientVersion(),
|
this._api.web3.clientVersion(),
|
||||||
this._api.net.version(),
|
this._api.net.version(),
|
||||||
this._api.parity.netChain(),
|
this._api.parity.netChain()
|
||||||
this._upgradeStore.checkUpgrade()
|
];
|
||||||
])
|
|
||||||
.then(([
|
if (nodeKindFull) {
|
||||||
netPeers, clientVersion, netVersion, netChain, upgradeStatus
|
statusPromises.push(this._upgradeStore.checkUpgrade());
|
||||||
]) => {
|
}
|
||||||
|
|
||||||
|
return Promise
|
||||||
|
.all(statusPromises)
|
||||||
|
.then(([nodeKind, netPeers, clientVersion, netVersion, netChain]) => {
|
||||||
const isTest = [
|
const isTest = [
|
||||||
'2', // morden
|
'2', // morden
|
||||||
'3', // ropsten
|
'3', // ropsten
|
||||||
'42' // kovan
|
'42' // kovan
|
||||||
].includes(netVersion);
|
].includes(netVersion);
|
||||||
|
|
||||||
|
const nodeKindFull = nodeKind &&
|
||||||
|
nodeKind.availability === 'personal' &&
|
||||||
|
nodeKind.capability === 'full';
|
||||||
|
|
||||||
const longStatus = {
|
const longStatus = {
|
||||||
|
nodeKind,
|
||||||
|
nodeKindFull,
|
||||||
netPeers,
|
netPeers,
|
||||||
clientVersion,
|
clientVersion,
|
||||||
netChain,
|
netChain,
|
||||||
|
@ -31,6 +31,8 @@ const initialState = {
|
|||||||
peers: []
|
peers: []
|
||||||
},
|
},
|
||||||
netVersion: '0',
|
netVersion: '0',
|
||||||
|
nodeKind: null,
|
||||||
|
nodeKindFull: null,
|
||||||
syncing: true,
|
syncing: true,
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user