Merge pull request #3899 from ethcore/warp-sync-rpcs
parity_chainStatus RPC for block gap info
This commit is contained in:
commit
a9f89b09e0
@ -66,6 +66,20 @@ export function outBlock (block) {
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function outChainStatus (status) {
|
||||||
|
if (status) {
|
||||||
|
Object.keys(status).forEach((key) => {
|
||||||
|
switch (key) {
|
||||||
|
case 'blockGap':
|
||||||
|
status[key] = status[key].map(outNumber);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
export function outDate (date) {
|
export function outDate (date) {
|
||||||
return new Date(outNumber(date).toNumber() * 1000);
|
return new Date(outNumber(date).toNumber() * 1000);
|
||||||
}
|
}
|
||||||
@ -77,6 +91,7 @@ export function outHistogram (histogram) {
|
|||||||
case 'bucketBounds':
|
case 'bucketBounds':
|
||||||
case 'counts':
|
case 'counts':
|
||||||
histogram[key] = histogram[key].map(outNumber);
|
histogram[key] = histogram[key].map(outNumber);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import { outBlock, outAccountInfo, outAddress, outDate, outHistogram, outNumber, outPeers, outReceipt, outSyncing, outTransaction, outTrace } from './output';
|
import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outNumber, outPeers, outReceipt, outSyncing, outTransaction, outTrace } from './output';
|
||||||
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
||||||
|
|
||||||
describe('api/format/output', () => {
|
describe('api/format/output', () => {
|
||||||
@ -114,6 +114,18 @@ describe('api/format/output', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('outChainStatus', () => {
|
||||||
|
it('formats blockGap values', () => {
|
||||||
|
const status = {
|
||||||
|
blockGap: [0x1234, '0x5678']
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(outChainStatus(status)).to.deep.equal({
|
||||||
|
blockGap: [new BigNumber(0x1234), new BigNumber(0x5678)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('outDate', () => {
|
describe('outDate', () => {
|
||||||
it('converts a second date in unix timestamp', () => {
|
it('converts a second date in unix timestamp', () => {
|
||||||
expect(outDate(0x57513668)).to.deep.equal(new Date('2016-06-03T07:48:56.000Z'));
|
expect(outDate(0x57513668)).to.deep.equal(new Date('2016-06-03T07:48:56.000Z'));
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { inAddress, inData, inHex, inNumber16, inOptions } from '../../format/input';
|
import { inAddress, inData, inHex, inNumber16, inOptions } from '../../format/input';
|
||||||
import { outAccountInfo, outAddress, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output';
|
import { outAccountInfo, outAddress, outChainStatus, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output';
|
||||||
|
|
||||||
export default class Parity {
|
export default class Parity {
|
||||||
constructor (transport) {
|
constructor (transport) {
|
||||||
@ -44,6 +44,12 @@ export default class Parity {
|
|||||||
.execute('parity_addReservedPeer', encode);
|
.execute('parity_addReservedPeer', encode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chainStatus () {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_chainStatus')
|
||||||
|
.then(outChainStatus);
|
||||||
|
}
|
||||||
|
|
||||||
changePassword (account, password, newPassword) {
|
changePassword (account, password, newPassword) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_changePassword', inAddress(account), password, newPassword);
|
.execute('parity_changePassword', inAddress(account), password, newPassword);
|
||||||
|
@ -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 BigNumber from 'bignumber.js';
|
||||||
import { TEST_HTTP_URL, mockHttp } from '../../../../test/mockRpc';
|
import { TEST_HTTP_URL, mockHttp } from '../../../../test/mockRpc';
|
||||||
import { isBigNumber } from '../../../../test/types';
|
import { isBigNumber } from '../../../../test/types';
|
||||||
|
|
||||||
@ -45,6 +46,22 @@ describe('api/rpc/parity', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('chainStatus', () => {
|
||||||
|
it('retrieves the chain status', () => {
|
||||||
|
mockHttp([{ method: 'parity_chainStatus', reply: {
|
||||||
|
result: {
|
||||||
|
'blockGap': [0x123, 0x456]
|
||||||
|
}
|
||||||
|
} }]);
|
||||||
|
|
||||||
|
return instance.chainStatus().then((result) => {
|
||||||
|
expect(result).to.deep.equal({
|
||||||
|
'blockGap': [new BigNumber(0x123), new BigNumber(0x456)]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('gasFloorTarget', () => {
|
describe('gasFloorTarget', () => {
|
||||||
it('returns the gasfloor, formatted', () => {
|
it('returns the gasfloor, formatted', () => {
|
||||||
mockHttp([{ method: 'parity_gasFloorTarget', reply: { result: '0x123456' } }]);
|
mockHttp([{ method: 'parity_gasFloorTarget', reply: { result: '0x123456' } }]);
|
||||||
|
@ -86,6 +86,22 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
chainStatus: {
|
||||||
|
desc: 'Returns the information on warp sync blocks',
|
||||||
|
params: [],
|
||||||
|
returns: {
|
||||||
|
type: Object,
|
||||||
|
desc: 'The status object',
|
||||||
|
details: {
|
||||||
|
blockGap: {
|
||||||
|
type: Array,
|
||||||
|
desc: 'Describes the gap in the blockchain, if there is one: (first, last)',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
checkRequest: {
|
checkRequest: {
|
||||||
desc: 'Returns the transactionhash of the requestId (received from parity_postTransaction) if the request was confirmed',
|
desc: 'Returns the transactionhash of the requestId (received from parity_postTransaction) if the request was confirmed',
|
||||||
params: [
|
params: [
|
||||||
|
@ -293,15 +293,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
|||||||
let chain_info = client.chain_info();
|
let chain_info = client.chain_info();
|
||||||
let current_block = U256::from(chain_info.best_block_number);
|
let current_block = U256::from(chain_info.best_block_number);
|
||||||
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
|
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
|
||||||
let gap = chain_info.ancient_block_number.map(|x| U256::from(x + 1))
|
|
||||||
.and_then(|first| chain_info.first_block_number.map(|last| (first, U256::from(last))));
|
|
||||||
let info = SyncInfo {
|
let info = SyncInfo {
|
||||||
starting_block: status.start_block_number.into(),
|
starting_block: status.start_block_number.into(),
|
||||||
current_block: current_block.into(),
|
current_block: current_block.into(),
|
||||||
highest_block: highest_block.into(),
|
highest_block: highest_block.into(),
|
||||||
warp_chunks_amount: warp_chunks_amount.map(|x| U256::from(x as u64)).map(Into::into),
|
warp_chunks_amount: warp_chunks_amount.map(|x| U256::from(x as u64)).map(Into::into),
|
||||||
warp_chunks_processed: warp_chunks_processed.map(|x| U256::from(x as u64)).map(Into::into),
|
warp_chunks_processed: warp_chunks_processed.map(|x| U256::from(x as u64)).map(Into::into),
|
||||||
block_gap: gap.map(|(x, y)| (x.into(), y.into())),
|
|
||||||
};
|
};
|
||||||
Ok(SyncStatus::Info(info))
|
Ok(SyncStatus::Info(info))
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,7 +40,7 @@ use v1::types::{
|
|||||||
Peers, Transaction, RpcSettings, Histogram,
|
Peers, Transaction, RpcSettings, Histogram,
|
||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo
|
OperationsInfo, ChainStatus,
|
||||||
};
|
};
|
||||||
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
|
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
|
||||||
use v1::helpers::dispatch::DEFAULT_MAC;
|
use v1::helpers::dispatch::DEFAULT_MAC;
|
||||||
@ -385,4 +385,17 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
|||||||
let updater = take_weak!(self.updater);
|
let updater = take_weak!(self.updater);
|
||||||
Ok(updater.info().map(Into::into))
|
Ok(updater.info().map(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chain_status(&self) -> Result<ChainStatus, Error> {
|
||||||
|
try!(self.active());
|
||||||
|
|
||||||
|
let chain_info = take_weak!(self.client).chain_info();
|
||||||
|
|
||||||
|
let gap = chain_info.ancient_block_number.map(|x| U256::from(x + 1))
|
||||||
|
.and_then(|first| chain_info.first_block_number.map(|last| (first, U256::from(last))));
|
||||||
|
|
||||||
|
Ok(ChainStatus {
|
||||||
|
block_gap: gap.map(|(x, y)| (x.into(), y.into())),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,16 +137,15 @@ fn rpc_eth_syncing() {
|
|||||||
// "sync" to 1000 blocks.
|
// "sync" to 1000 blocks.
|
||||||
// causes TestBlockChainClient to return 1000 for its best block number.
|
// causes TestBlockChainClient to return 1000 for its best block number.
|
||||||
tester.add_blocks(1000, EachBlockWith::Nothing);
|
tester.add_blocks(1000, EachBlockWith::Nothing);
|
||||||
*tester.client.ancient_block.write() = Some((H256::new(), 5));
|
|
||||||
*tester.client.first_block.write() = Some((H256::from(U256::from(1234)), 3333));
|
|
||||||
|
|
||||||
let true_res = r#"{"jsonrpc":"2.0","result":{"blockGap":["0x6","0xd05"],"currentBlock":"0x3e8","highestBlock":"0x9c4","startingBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null},"id":1}"#;
|
|
||||||
|
let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x3e8","highestBlock":"0x9c4","startingBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null},"id":1}"#;
|
||||||
assert_eq!(tester.io.handle_request_sync(request), Some(true_res.to_owned()));
|
assert_eq!(tester.io.handle_request_sync(request), Some(true_res.to_owned()));
|
||||||
|
|
||||||
*tester.client.ancient_block.write() = None;
|
*tester.client.ancient_block.write() = None;
|
||||||
*tester.client.first_block.write() = None;
|
*tester.client.first_block.write() = None;
|
||||||
|
|
||||||
let snap_res = r#"{"jsonrpc":"2.0","result":{"blockGap":null,"currentBlock":"0x3e8","highestBlock":"0x9c4","startingBlock":"0x0","warpChunksAmount":"0x32","warpChunksProcessed":"0x18"},"id":1}"#;
|
let snap_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x3e8","highestBlock":"0x9c4","startingBlock":"0x0","warpChunksAmount":"0x32","warpChunksProcessed":"0x18"},"id":1}"#;
|
||||||
tester.snapshot.set_status(RestorationStatus::Ongoing {
|
tester.snapshot.set_status(RestorationStatus::Ongoing {
|
||||||
state_chunks: 40,
|
state_chunks: 40,
|
||||||
block_chunks: 10,
|
block_chunks: 10,
|
||||||
|
@ -421,3 +421,18 @@ fn rpc_parity_local_transactions() {
|
|||||||
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_parity_chain_status() {
|
||||||
|
use util::{H256, U256};
|
||||||
|
|
||||||
|
let deps = Dependencies::new();
|
||||||
|
let io = deps.default_client();
|
||||||
|
|
||||||
|
*deps.client.ancient_block.write() = Some((H256::default(), 5));
|
||||||
|
*deps.client.first_block.write() = Some((H256::from(U256::from(1234)), 3333));
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "parity_chainStatus", "params":[], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":{"blockGap":["0x6","0xd05"]},"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
@ -26,7 +26,7 @@ use v1::types::{
|
|||||||
Peers, Transaction, RpcSettings, Histogram,
|
Peers, Transaction, RpcSettings, Histogram,
|
||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo
|
OperationsInfo, ChainStatus,
|
||||||
};
|
};
|
||||||
|
|
||||||
build_rpc_trait! {
|
build_rpc_trait! {
|
||||||
@ -174,5 +174,9 @@ build_rpc_trait! {
|
|||||||
/// Get information concerning the latest releases if available.
|
/// Get information concerning the latest releases if available.
|
||||||
#[rpc(name = "parity_releasesInfo")]
|
#[rpc(name = "parity_releasesInfo")]
|
||||||
fn releases_info(&self) -> Result<Option<OperationsInfo>, Error>;
|
fn releases_info(&self) -> Result<Option<OperationsInfo>, Error>;
|
||||||
|
|
||||||
|
/// Get the current chain status.
|
||||||
|
#[rpc(name = "parity_chainStatus")]
|
||||||
|
fn chain_status(&self) -> Result<ChainStatus, Error>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,10 @@ pub use self::filter::{Filter, FilterChanges};
|
|||||||
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
||||||
pub use self::index::Index;
|
pub use self::index::Index;
|
||||||
pub use self::log::Log;
|
pub use self::log::Log;
|
||||||
pub use self::sync::{SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo, TransactionStats};
|
pub use self::sync::{
|
||||||
|
SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo,
|
||||||
|
TransactionStats, ChainStatus
|
||||||
|
};
|
||||||
pub use self::transaction::{Transaction, RichRawTransaction, LocalTransactionStatus};
|
pub use self::transaction::{Transaction, RichRawTransaction, LocalTransactionStatus};
|
||||||
pub use self::transaction_request::TransactionRequest;
|
pub use self::transaction_request::TransactionRequest;
|
||||||
pub use self::receipt::Receipt;
|
pub use self::receipt::Receipt;
|
||||||
|
@ -37,9 +37,6 @@ pub struct SyncInfo {
|
|||||||
/// Warp sync snpashot chunks processed.
|
/// Warp sync snpashot chunks processed.
|
||||||
#[serde(rename="warpChunksProcessed")]
|
#[serde(rename="warpChunksProcessed")]
|
||||||
pub warp_chunks_processed: Option<U256>,
|
pub warp_chunks_processed: Option<U256>,
|
||||||
/// Describes the gap in the blockchain, if there is one: (first, last)
|
|
||||||
#[serde(rename="blockGap")]
|
|
||||||
pub block_gap: Option<(U256, U256)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Peers info
|
/// Peers info
|
||||||
@ -162,17 +159,25 @@ impl From<SyncTransactionStats> for TransactionStats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Chain status.
|
||||||
|
#[derive(Default, Debug, Serialize)]
|
||||||
|
pub struct ChainStatus {
|
||||||
|
/// Describes the gap in the blockchain, if there is one: (first, last)
|
||||||
|
#[serde(rename="blockGap")]
|
||||||
|
pub block_gap: Option<(U256, U256)>,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use super::{SyncInfo, SyncStatus, Peers, TransactionStats};
|
use super::{SyncInfo, SyncStatus, Peers, TransactionStats, ChainStatus};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_sync_info() {
|
fn test_serialize_sync_info() {
|
||||||
let t = SyncInfo::default();
|
let t = SyncInfo::default();
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"{"startingBlock":"0x0","currentBlock":"0x0","highestBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null,"blockGap":null}"#);
|
assert_eq!(serialized, r#"{"startingBlock":"0x0","currentBlock":"0x0","highestBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -190,16 +195,19 @@ mod tests {
|
|||||||
|
|
||||||
let t = SyncStatus::Info(SyncInfo::default());
|
let t = SyncStatus::Info(SyncInfo::default());
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"{"startingBlock":"0x0","currentBlock":"0x0","highestBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null,"blockGap":null}"#);
|
assert_eq!(serialized, r#"{"startingBlock":"0x0","currentBlock":"0x0","highestBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_block_gap() {
|
fn test_serialize_block_gap() {
|
||||||
let mut t = SyncInfo::default();
|
let mut t = ChainStatus::default();
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"blockGap":null}"#);
|
||||||
|
|
||||||
t.block_gap = Some((1.into(), 5.into()));
|
t.block_gap = Some((1.into(), 5.into()));
|
||||||
|
|
||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"{"startingBlock":"0x0","currentBlock":"0x0","highestBlock":"0x0","warpChunksAmount":null,"warpChunksProcessed":null,"blockGap":["0x1","0x5"]}"#)
|
assert_eq!(serialized, r#"{"blockGap":["0x1","0x5"]}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user