Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reporter: setup zmq block subscription #92

Merged
merged 44 commits into from
Nov 2, 2022

Conversation

gusin13
Copy link
Collaborator

@gusin13 gusin13 commented Oct 24, 2022

Fixes

https://babylon-chain.atlassian.net/browse/BM-208

Description

This PR adds zmq-based block subscription support in the reporter.

Setup

  1. Download bitcoin core - https://bitcoin.org/en/wallets/desktop/mac/bitcoincore/
  2. Add following in bitcoin.conf
regtest=1
server=1
rpcuser=rpcuser
rpcpassword=rpcpass
zmqpubrawblock=tcp://127.0.0.1:29000
zmqpubrawtx=tcp://127.0.0.1:29000
zmqpubhashtx=tcp://127.0.0.1:29000
zmqpubhashblock=tcp://127.0.0.1:29000
zmqpubsequence=tcp://127.0.0.1:29000
  1. Run bitcoin-cli getzmqnotifications in terminal to confirm if notifications are enabled

Screen Shot 2022-10-29 at 11 48 17 PM

  1. Run the reporter
  2. Generate new block bitcoin-cli -generate 1

Screen Shot 2022-10-29 at 11 52 42 PM

  1. ZMQ will handle this notification in reporter.

@gusin13 gusin13 force-pushed the BM-208-investigate-zmq-for-bitcoind branch from 8c372ab to 5afdeec Compare October 29, 2022 17:35
@gusin13 gusin13 changed the title Setup ZMQ in reporter Setup ZMQ subscription in Reporter Oct 30, 2022
@gusin13 gusin13 changed the title Setup ZMQ subscription in Reporter Setup ZMQ based block handling in Reporter Oct 30, 2022
@gusin13 gusin13 changed the title Setup ZMQ based block handling in Reporter Setup zmq based block handling in reporter. Oct 30, 2022
@gusin13 gusin13 changed the title Setup zmq based block handling in reporter. reporter: setup zmq block subscription. Oct 30, 2022
@gusin13 gusin13 changed the title reporter: setup zmq block subscription. reporter: setup zmq block subscription Oct 30, 2022
@gusin13 gusin13 marked this pull request as ready for review October 30, 2022 02:25
Copy link
Member

@SebastianElvis SebastianElvis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for figuring out all the ZMQ stuff, which looks challenging! Left some comments on the overall design.

Comment on lines 5 to 7
no-client-tls: true
ca-file: $TESTNET_PATH/bitcoin/rpc.cert
endpoint: localhost:18556
endpoint: localhost:18443
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we change these parameters?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the port required for bitcoind regtest

tx-fee: 2500
wallet-endpoint: localhost:18554
wallet-password: walletpass
wallet-name: default
wallet-lock-time: 10
wallet-ca-file: $TESTNET_PATH/bitcoin/rpc-wallet.cert
net-params: simnet
net-params: regtest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe worth adding some comments about the supported net parameters of Btcd and bitcoind.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

Comment on lines 15 to 18

TransactionRemoved

TransactionAdded
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we interested in these events?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, we are not using it anywhere, I added it because these are returned from the sequence socket.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I would say we ignore these events, since they are not related to blocks while our event type is called BlockEvent.

sample-vigilante.yml Outdated Show resolved Hide resolved
HTTPPostMode: true,
User: cfg.Username,
Pass: cfg.Password,
DisableTLS: cfg.DisableClientTLS,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this because bitcoind does not support TLS?

Copy link
Collaborator Author

@gusin13 gusin13 Nov 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, it doesn't support TLS.

panic(err)
}

c.ZmqSequenceMsgChan = ch
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we filter BlockConnected and BlockDisconnected events from ZmqSequenceMsgChan, and forward these events to BlockEventChan in a goroutine, so that we can omit the public ZmqSequenceMsgChan channel in Client?

Copy link
Collaborator Author

@gusin13 gusin13 Oct 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in that case ZmqSequenceMsgChan would still need to be a public channel as we process events in different package here ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use a unified channel, then the two different handlers can be merged, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so I think you mean we don't need ZmqSequenceMsgChan, we should directly push messages to BlockEventChan from zmq library here. Yes that can be done 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I feel like this can simplify the design a little bit

Copy link
Collaborator Author

@gusin13 gusin13 Oct 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was refraining to use bbn/vigilante code inside zmq package as I wanted to keep it separate but I agree above suggestion will simplify stuff, will fix it soon.

Note

As the zmq socket just gives us block hash, to make the BlockEvent , I will need to fetch header/height using rpc client , so need to pass rpc client info in the zmq lib as well.

Copy link
Member

@SebastianElvis SebastianElvis Nov 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, for modularity I think we can make events like TransactionRemoved and ZmqSequenceMsgChan to be a part of this Zmq library, while making BTC client to only consume block-related events.

@@ -32,6 +35,17 @@ func (cfg *BTCConfig) Validate() error {
if _, ok := types.GetValidNetParams()[cfg.NetParams]; !ok {
return errors.New("invalid net params")
}

if cfg.EnableZmq {
if cfg.ZmqPubAddress == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a TODO on regex check of IP address

func (r *Reporter) blockEventHandler() {
defer r.wg.Done()
quit := r.quitChan()

for {
select {
case event := <-r.btcClient.BlockEventChan:
case event, open := <-r.btcClient.BlockEventChan:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -23,6 +31,56 @@ func (r *Reporter) blockEventHandler() {
}
}

// zmqSequenceMessageHandler handles sequence messages from the ZMQ sequence socket.
func (r *Reporter) zmqSequenceMessageHandler() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be replaced by the redirection approach suggested above

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@@ -0,0 +1,115 @@
package zmq
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the ZMQ library, which is a tough one! Since only btcclient will use this zmq library, can we move zmq/ to btcclient/zmq? In addition, IIRC some of the code is from an open-source codebase, so perhaps we can attach URL on the origin of these code here.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a reference to open source code at start of the package but couldn't move zmq inside btcclient due to cyclic import issues.

Copy link
Member

@SebastianElvis SebastianElvis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thanks for figuring these Zmq things out!

}
if backend != rpcclient.Btcd {
return nil, fmt.Errorf("NewWithBlockSubscriber is only compatible with Btcd")
// ensure we are using bitcoind as Bitcoin node, as zmq is only supported by bitcoind
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks between L50-L56 can happen before L45, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

c.blockEventChan <- types.NewBlockEvent(event, ib.Height, ib.Header)
}

func (c *Client) getBlockByHash(blockHash *chainhash.Hash) (*types.IndexedBlock, *wire.MsgBlock, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function looks like the cause why the Zmq client needs the pointer to the BTC client. It would be good if we avoid them referencing each other. Is it possible to

  • remove the height from BlockEvent and remove this function and the pointer to the BTC client, or
  • pass BlockEvent with zero height when using Zmq?

since the height in BlockEvent is not used anyway. This also might allow us to put zmq/ under btcclient/ as well.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZMQ only needs BTC client to query BTC. Instead pointing to BTC client , I inserted rpc client inside zmq client so it can query directly here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this PR I inserted rpc client in the zmq client here

I was asking the possibility to avoid the zmq client to query BTC client. There might be some dependency issues when BTC client and Zmq client are referencing each other. From a modularity point of view the Zmq client should not refer to BTC client as well. The ideal case would be that Zmq client pushes messages to the BlockEvent channel without querying BTC client.

Copy link
Collaborator Author

@gusin13 gusin13 Nov 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ideal case would be that Zmq client pushes messages to the BlockEvent channel without querying BTC client.

Sure this is possible.

Is it possible to

  • remove the height from BlockEvent and remove this function and the pointer to the BTC client, or
  • pass BlockEvent with zero height when using Zmq?

I think this might not be work as zmq socket just provides block hash, it doesn't give us header or height so omitting height won't be suffice. We should rather change BlockEvent to accept just hash as both bitcoind and btcd provides hash on notification arrival. We can then query BTC when this block is handled in blockEventHandler

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added TODO for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I would also prefer removing the height from BlockEvent. Let's do it in subsequent PRs. 👍

@gusin13 gusin13 force-pushed the BM-208-investigate-zmq-for-bitcoind branch from 815f460 to d53144e Compare November 2, 2022 02:37
@gusin13 gusin13 merged commit f743696 into main Nov 2, 2022
@gusin13 gusin13 deleted the BM-208-investigate-zmq-for-bitcoind branch November 2, 2022 02:40
Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Minor comments

HTTPPostMode: true,
User: cfg.Username,
Pass: cfg.Password,
DisableTLS: cfg.DisableClientTLS,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When bitcoind is used, DisableClientTLS should always be true, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, will fix it in next PR.

if err != nil {
return nil, fmt.Errorf("failed to get BTC backend: %v", err)
}
if backend != rpcclient.BitcoindPost19 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is BitcoindPost19?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are enums given by the rpc client library

  • BTCD is used for btcd
  • BitcoindPost19 is used for bitcoind

Check here

case types.WebsocketMode:
notificationHandlers := rpcclient.NotificationHandlers{
OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) {
log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These debugging logs only appear on a btcd connection. To be more consistent, maybe we could add those in the consumer channel?

WalletName string `mapstructure:"wallet-name"`
WalletCAFile string `mapstructure:"wallet-ca-file"`
WalletLockTime int64 `mapstructure:"wallet-lock-time"` // time duration in which the wallet remains unlocked, in seconds
TxFee btcutil.Amount `mapstructure:"tx-fee"` // BTC tx fee, in BTC
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in Satoshi

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, I will fix it in the next PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants