core: accept two-side channels for sub/unsub, read on unsub

Blockchain's notificationDispatcher sends events to channels and these
channels must be read from. Unfortunately, regular service shutdown procedure
does unsubscription first (outside of the read loop) and only then drains the
channel. While it waits for unsubscription request to be accepted
notificationDispatcher can try pushing more data into the same channel which
will lead to a deadlock. Reading in the same method solves this, any number of
events can be pushed until unsub channel accepts the data.
This commit is contained in:
Roman Khimov 2022-08-19 20:47:55 +03:00
parent dea75a4211
commit eeeb0f6f0e
7 changed files with 83 additions and 53 deletions

View file

@ -26,7 +26,7 @@ import (
type FakeChain struct {
config.ProtocolConfiguration
*mempool.Pool
blocksCh []chan<- *block.Block
blocksCh []chan *block.Block
Blockheight uint32
PoolTxF func(*transaction.Transaction) error
poolTxWithData func(*transaction.Transaction, interface{}, *mempool.Pool) error
@ -351,22 +351,22 @@ func (chain *FakeChain) PoolTx(tx *transaction.Transaction, _ ...*mempool.Pool)
}
// SubscribeForBlocks implements the Blockchainer interface.
func (chain *FakeChain) SubscribeForBlocks(ch chan<- *block.Block) {
func (chain *FakeChain) SubscribeForBlocks(ch chan *block.Block) {
chain.blocksCh = append(chain.blocksCh, ch)
}
// SubscribeForExecutions implements the Blockchainer interface.
func (chain *FakeChain) SubscribeForExecutions(ch chan<- *state.AppExecResult) {
func (chain *FakeChain) SubscribeForExecutions(ch chan *state.AppExecResult) {
panic("TODO")
}
// SubscribeForNotifications implements the Blockchainer interface.
func (chain *FakeChain) SubscribeForNotifications(ch chan<- *state.ContainedNotificationEvent) {
func (chain *FakeChain) SubscribeForNotifications(ch chan *state.ContainedNotificationEvent) {
panic("TODO")
}
// SubscribeForTransactions implements the Blockchainer interface.
func (chain *FakeChain) SubscribeForTransactions(ch chan<- *transaction.Transaction) {
func (chain *FakeChain) SubscribeForTransactions(ch chan *transaction.Transaction) {
panic("TODO")
}
@ -384,7 +384,7 @@ func (chain *FakeChain) VerifyWitness(util.Uint160, hash.Hashable, *transaction.
}
// UnsubscribeFromBlocks implements the Blockchainer interface.
func (chain *FakeChain) UnsubscribeFromBlocks(ch chan<- *block.Block) {
func (chain *FakeChain) UnsubscribeFromBlocks(ch chan *block.Block) {
for i, c := range chain.blocksCh {
if c == ch {
if i < len(chain.blocksCh) {
@ -396,17 +396,17 @@ func (chain *FakeChain) UnsubscribeFromBlocks(ch chan<- *block.Block) {
}
// UnsubscribeFromExecutions implements the Blockchainer interface.
func (chain *FakeChain) UnsubscribeFromExecutions(ch chan<- *state.AppExecResult) {
func (chain *FakeChain) UnsubscribeFromExecutions(ch chan *state.AppExecResult) {
panic("TODO")
}
// UnsubscribeFromNotifications implements the Blockchainer interface.
func (chain *FakeChain) UnsubscribeFromNotifications(ch chan<- *state.ContainedNotificationEvent) {
func (chain *FakeChain) UnsubscribeFromNotifications(ch chan *state.ContainedNotificationEvent) {
panic("TODO")
}
// UnsubscribeFromTransactions implements the Blockchainer interface.
func (chain *FakeChain) UnsubscribeFromTransactions(ch chan<- *transaction.Transaction) {
func (chain *FakeChain) UnsubscribeFromTransactions(ch chan *transaction.Transaction) {
panic("TODO")
}