-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Polkadot service #82
Polkadot service #82
Changes from 1 commit
f22cbda
a7e3f9d
197aaf2
9cb9410
6147304
e96486e
0d5fe7c
c808a91
b0f85b0
158a000
1bbee71
dd30b9c
41e28f6
7c0ea3d
da31b51
9e38d2d
884d3a1
153b93b
a82a2e3
1572f14
a4f656f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,8 @@ | |
|
|
||
| //! Substrate Client | ||
|
|
||
| use multiqueue; | ||
| use parking_lot::Mutex; | ||
| use primitives::{self, block, AuthorityId}; | ||
| use primitives::block::Id as BlockId; | ||
| use primitives::storage::{StorageKey, StorageData}; | ||
|
|
@@ -28,10 +30,11 @@ use blockchain::{self, Info as ChainInfo, Backend as ChainBackend}; | |
| use {error, in_mem, block_builder, runtime_io, bft}; | ||
|
|
||
| /// Polkadot Client | ||
| #[derive(Debug)] | ||
| pub struct Client<B, E> where B: backend::Backend { | ||
| backend: B, | ||
| executor: E, | ||
| import_notification_sink: Mutex<multiqueue::BroadcastFutSender<BlockImportNotification>>, | ||
| import_notification_stream: Mutex<multiqueue::BroadcastFutReceiver<BlockImportNotification>>, | ||
| } | ||
|
|
||
| /// Client info | ||
|
|
@@ -82,6 +85,32 @@ pub enum BlockStatus { | |
| Unknown, | ||
| } | ||
|
|
||
| /// Block data origin. | ||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||
| pub enum BlockOrigin { | ||
| /// Genesis block built into the client. | ||
| Genesis, | ||
| /// Block is part of the initial sync with the network. | ||
| NetworkInitialSync, | ||
| /// Block was broadcasted on the network. | ||
| NetworkBroadcast, | ||
| /// Block that was collated by this node. | ||
| Own, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what does this mean in the context of the 2-phase commit?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means that the block body was generated on this machine and was not received from the network.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the block body is almost always generated on another machine, but any block bodies coming directly from the consensus process have already been evaluated
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a variant for that. |
||
| /// Block was imported from a file. | ||
| File, | ||
| } | ||
|
|
||
| /// Summary of an imported block | ||
| #[derive(Clone, Debug)] | ||
| pub struct BlockImportNotification { | ||
| /// Imported block origin. | ||
| pub origin: BlockOrigin, | ||
| /// Imported block header. | ||
| pub header: block::Header, | ||
| /// Is this the new best block. | ||
| pub is_new_best: bool, | ||
| } | ||
|
|
||
| /// A header paired with a justification which has already been checked. | ||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||
| pub struct JustifiedHeader { | ||
|
|
@@ -122,6 +151,7 @@ impl<B, E> Client<B, E> where | |
| where | ||
| F: FnOnce() -> (block::Header, Vec<(Vec<u8>, Vec<u8>)>) | ||
| { | ||
| let (sink, stream) = multiqueue::broadcast_fut_queue(64); | ||
| if backend.blockchain().header(BlockId::Number(0))?.is_none() { | ||
| trace!("Empty database, writing genesis block"); | ||
| let (genesis_header, genesis_store) = build_genesis(); | ||
|
|
@@ -133,9 +163,16 @@ impl<B, E> Client<B, E> where | |
| Ok(Client { | ||
| backend, | ||
| executor, | ||
| import_notification_sink: Mutex::new(sink), | ||
| import_notification_stream: Mutex::new(stream), | ||
| }) | ||
| } | ||
|
|
||
| /// Get block import event stream. | ||
| pub fn import_notification_stream(&self) -> multiqueue::BroadcastFutReceiver<BlockImportNotification> { | ||
| self.import_notification_stream.lock().add_stream() | ||
| } | ||
|
|
||
| /// Get a reference to the state at a given block. | ||
| pub fn state_at(&self, block: &BlockId) -> error::Result<B::State> { | ||
| self.backend.state_at(*block) | ||
|
|
@@ -236,6 +273,7 @@ impl<B, E> Client<B, E> where | |
| /// Queue a block for import. | ||
| pub fn import_block( | ||
| &self, | ||
| origin: BlockOrigin, | ||
| header: JustifiedHeader, | ||
| body: Option<block::Body>, | ||
| ) -> error::Result<ImportResult> { | ||
|
|
@@ -261,9 +299,21 @@ impl<B, E> Client<B, E> where | |
|
|
||
| let is_new_best = header.number == self.backend.blockchain().info()?.best_number + 1; | ||
| trace!("Imported {}, (#{}), best={}", block::HeaderHash::from(header.blake2_256()), header.number, is_new_best); | ||
| transaction.set_block_data(header, body, Some(justification.uncheck().into()), is_new_best)?; | ||
| transaction.set_block_data(header.clone(), body, Some(justification.uncheck().into()), is_new_best)?; | ||
| transaction.set_storage(overlay.drain())?; | ||
| self.backend.commit_operation(transaction)?; | ||
|
|
||
| if origin == BlockOrigin::NetworkBroadcast || origin == BlockOrigin::Own { | ||
| let notification = BlockImportNotification { | ||
| origin: origin, | ||
| header: header, | ||
| is_new_best: is_new_best, | ||
| }; | ||
| if let Err(e) = self.import_notification_sink.lock().try_send(notification) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this fails if the buffer is full; seems dangerous to discard the notification in this case. maybe use the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Import is more important and should not block on the notification handler. Normally this should never happen but if it does, skipping a notification is fine since there will be a new block eventually anyway. The handlers are not supposed to expect to receive notifications for every block anyway. It is quite possible that the node goes to sleep or loses connectivity for a while and when it goes back online there won't be any notifications for all the blocks that arrived in the meantime.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
this is reasoning about "eventually" a little too long term for me to be comfortable using this in practice.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Increased the buffer to 65536 for now. Unfortunately it is preallocated.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. still dangerous but probably workable for now. we should write a fix after this PR -- maybe a 50ms timer where the same chain head being observed twice in a row starts consensus?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll address that in the following PR. Probably ny replacing |
||
| warn!("Error queueing block import notification: {:?}", e); | ||
| } | ||
| } | ||
|
|
||
| Ok(ImportResult::Queued) | ||
| } | ||
|
|
||
|
|
@@ -335,7 +385,7 @@ impl<B, E> bft::BlockImport for Client<B, E> | |
| justification, | ||
| }; | ||
|
|
||
| let _ = self.import_block(justified_header, Some(block.transactions)); | ||
| let _ = self.import_block(BlockOrigin::Genesis, justified_header, Some(block.transactions)); | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aren't all blocks broadcast over the network in some sense? doesn't it make more sense to provide hints about whether a block is the head of the chain or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The head hint is provided as a separate parameter to
importfunction. This is for something else. Mainly for logging and possibly skipping certain checks for local blocks.