Skip to content

Commit

Permalink
[wip] multi: add notifywork.
Browse files Browse the repository at this point in the history
  • Loading branch information
dnldd committed May 8, 2018
1 parent fd99f57 commit ce7b740
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 11 deletions.
84 changes: 84 additions & 0 deletions blockmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ const (
// do expensive lottery data look ups for these blocks. It is
// equivalent to 24 hours of work on mainnet.
maxLotteryDataBlockDelta = 288

// templateRegenSeconds is the number of seconds that must pass before
// a new template is generated when the previous block hash has not
// changed and there have been changes to the available transactions
// in the memory pool.
templateRegenSeconds = 15
)

// zeroHash is the zero value hash (all zeros). It is defined as a convenience.
Expand Down Expand Up @@ -286,6 +292,13 @@ type setParentTemplateMsg struct {
reply chan setParentTemplateResponse
}

// RegenTemplateMsg is a message sent to regenerate a block template.
type RegenTemplateMsg struct{}

// SetNextTemplateRegenMsg is a message sent to set a future time for the next
// block template regeneration.
type SetNextTemplateRegenMsg struct{}

// setParentTemplateResponse is a response sent to the reply channel of a
// setParentTemplateMsg.
type setParentTemplateResponse struct {
Expand Down Expand Up @@ -409,6 +422,13 @@ type blockManager struct {
lotteryDataBroadcast map[chainhash.Hash]struct{}
lotteryDataBroadcastMutex sync.RWMutex

// the following fields handle block template regeneration.
templateChan chan interface{}
lastRegen time.Time
nextRegen time.Time
nextRegenUpdated bool
regenTicker *time.Ticker

cachedCurrentTemplate *BlockTemplate
cachedParentTemplate *BlockTemplate
AggressiveMining bool
Expand Down Expand Up @@ -1929,6 +1949,70 @@ out:
bmgrLog.Trace("Block handler done")
}

// evaluateBlockTemplate generates a new block template if the current
// template has been invalidated. It must be run as a goroutine.
func (b *blockManager) evaluateBlockTemplate() {
b.regenTicker = time.NewTicker(time.Second)
b.nextRegen = b.server.txMemPool.LastUpdated().
Add(time.Second * templateRegenSeconds)
out:
for {
select {
case msg := <-b.templateChan:
switch msg.(type) {
case RegenTemplateMsg:
// Choose a payment address at random.
payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))]
template, err := NewBlockTemplate(b.server.rpcServer.policy,
b.server, payToAddr)
if err != nil {
bmgrLog.Errorf("Failed to create new block template: %v", err)
}

if template == nil {
// This happens if the template is returned nil because
// there are not enough voters on HEAD and there is
// currently an unsuitable parent cached template to
// try building off of.
bmgrLog.Error("Failed to create new block template: not " +
"enough voters and failed to find a suitable " +
"parent template to build from")
}

// Update cached templates.
b.SetParentTemplate(b.cachedCurrentTemplate)
b.SetCurrentTemplate(template)

// Set the next update time.
b.lastRegen = time.Now()
b.nextRegen = b.lastRegen.Add(time.Second * templateRegenSeconds)
b.nextRegenUpdated = false

case SetNextTemplateRegenMsg:
// Extend the next template regeneration time.
if !b.nextRegenUpdated {
b.nextRegen = b.nextRegen.Add(time.Second * templateRegenSeconds)
b.nextRegenUpdated = true
}
}
case <-b.regenTicker.C:
// Assert the mempool has been updated since the last template regeneration.
if b.server.txMemPool.LastUpdated().After(b.lastRegen) {
// Regenerate block template when the threshold is met.
if b.server.txMemPool.LastUpdated().Equal(b.nextRegen) ||
b.server.txMemPool.LastUpdated().After(b.nextRegen) {
b.templateChan <- RegenTemplateMsg{}
}
}

case <-b.quit:
break out
}
}

b.regenTicker.Stop()
}

// handleNotifyMsg handles notifications from blockchain. It does things such
// as request orphan block parents and relay accepted blocks to connected peers.
func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) {
Expand Down
20 changes: 20 additions & 0 deletions dcrjson/chainsvrwscmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ func NewNotifyBlocksCmd() *NotifyBlocksCmd {
return &NotifyBlocksCmd{}
}

// NotifyWorkCmd defines the notifywork JSON-RPC command.
type NotifyWorkCmd struct{}

// NewNotifyWorkCmd returns a new instance which can be used to issue a
// notifywork JSON-RPC command.
func NewNotifyWorkCmd() *NotifyWorkCmd {
return &NotifyWorkCmd{}
}

// NotifyWinningTicketsCmd is a type handling custom marshaling and
// unmarshaling of notifywinningtickets JSON websocket extension
// commands.
Expand Down Expand Up @@ -111,6 +120,15 @@ func NewStopNotifyBlocksCmd() *StopNotifyBlocksCmd {
return &StopNotifyBlocksCmd{}
}

// StopNotifyWorkCmd defines the stopnotifywork JSON-RPC command.
type StopNotifyWorkCmd struct{}

// NewStopNotifyWorkCmd returns a new instance which can be used to issue a
// stopnotifywork JSON-RPC command.
func NewStopNotifyWorkCmd() *StopNotifyWorkCmd {
return &StopNotifyWorkCmd{}
}

// NotifyNewTransactionsCmd defines the notifynewtransactions JSON-RPC command.
type NotifyNewTransactionsCmd struct {
Verbose *bool `jsonrpcdefault:"false"`
Expand Down Expand Up @@ -168,6 +186,7 @@ func init() {
MustRegisterCmd("authenticate", (*AuthenticateCmd)(nil), flags)
MustRegisterCmd("loadtxfilter", (*LoadTxFilterCmd)(nil), flags)
MustRegisterCmd("notifyblocks", (*NotifyBlocksCmd)(nil), flags)
MustRegisterCmd("notifywork", (*NotifyWorkCmd)(nil), flags)
MustRegisterCmd("notifynewtransactions", (*NotifyNewTransactionsCmd)(nil), flags)
MustRegisterCmd("notifynewtickets", (*NotifyNewTicketsCmd)(nil), flags)
MustRegisterCmd("notifyspentandmissedtickets",
Expand All @@ -178,6 +197,7 @@ func init() {
(*NotifyWinningTicketsCmd)(nil), flags)
MustRegisterCmd("session", (*SessionCmd)(nil), flags)
MustRegisterCmd("stopnotifyblocks", (*StopNotifyBlocksCmd)(nil), flags)
MustRegisterCmd("stopnotifywork", (*StopNotifyWorkCmd)(nil), flags)
MustRegisterCmd("stopnotifynewtransactions", (*StopNotifyNewTransactionsCmd)(nil), flags)
MustRegisterCmd("rescan", (*RescanCmd)(nil), flags)
}
19 changes: 19 additions & 0 deletions dcrjson/chainsvrwsntfns.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const (
// the chain server that a block has been connected.
BlockConnectedNtfnMethod = "blockconnected"

// WorkAvialableNtfnMethod is the method used for notifications from
// the chain server that a block is available to mined.
WorkAvailableNtfnMethod = "workavailable"

// BlockDisconnectedNtfnMethod is the method used for notifications from
// the chain server that a block has been disconnected.
BlockDisconnectedNtfnMethod = "blockdisconnected"
Expand Down Expand Up @@ -52,6 +56,21 @@ func NewBlockConnectedNtfn(header string, subscribedTxs []string) *BlockConnecte
}
}

// WorkAvailableNtfn models the data from the workavailable JSON-RPC notification.
type WorkAvailableNtfn struct {
Data string `json:"data"`
Target string `json:"target"`
}

// NewWorkNtfn returns a new instance which can be used to issue a
// newwork JSON-RPC notification.
func NewWorkAvailableNtfn(data string, target string) *WorkAvailableNtfn {
return &WorkAvailableNtfn{
Data: data,
Target: target,
}
}

// BlockDisconnectedNtfn defines the blockdisconnected JSON-RPC notification.
type BlockDisconnectedNtfn struct {
Header string `json:"header"`
Expand Down
47 changes: 37 additions & 10 deletions docs/json_rpc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -693,16 +693,18 @@ user. Click the method name for further details such as parameter and return in
|---|------|-----------|-------------|
|1|[authenticate](#authenticate)|Authenticate the connection against the username and passphrase configured for the RPC server.<br /><br />NOTE: This is only required if an HTTP Authorization header is not being used.|None|
|2|[notifyblocks](#notifyblocks)|Send notifications when a block is connected or disconnected from the best chain.|[blockconnected](#blockconnected) and [blockdisconnected](#blockdisconnected)|
|3|[stopnotifyblocks](#stopnotifyblocks)|Cancel registered notifications for whenever a block is connected or disconnected from the main (best) chain. |None|
|4|[notifyreceived](#notifyreceived)|Send notifications when a txout spends to an address.|[recvtx](#recvtx) and [redeemingtx](#redeemingtx)|
|5|[stopnotifyreceived](#stopnotifyreceived)|Cancel registered notifications for when a txout spends to any of the passed addresses.|None|
|6|[notifyspent](#notifyspent)|Send notification when a txout is spent.|[redeemingtx](#redeemingtx)|
|7|[stopnotifyspent](#stopnotifyspent)|Cancel registered spending notifications for each passed outpoint.|None|
|8|[loadtxfilter](#loadtxfilter)|Load, add to, or reload a websocket client's transaction filter for mempool transactions, new blocks and rescanblocks.|[relevanttxaccepted](#relevanttxaccepted)|
|9|[rescan](#rescan)|Rescan block chain for transactions to addresses and spent transaction outpoints.|[recvtx](#recvtx), [redeemingtx](#redeemingtx), [rescanprogress](#rescanprogress), and [rescanfinished](#rescanfinished) |
|10|[notifynewtransactions](#notifynewtransactions)|Send notifications for all new transactions as they are accepted into the mempool.|[txaccepted](#txaccepted) or [txacceptedverbose](#txacceptedverbose)|
|11|[stopnotifynewtransactions](#stopnotifynewtransactions)|Stop sending either a txaccepted or a txacceptedverbose notification when a new transaction is accepted into the mempool.|None|
|12|[session](#session)|Return details regarding a websocket client's current connection.|None|
|3|[notifywork](#notifywork)|Send notifications when a block is available to be mined.| [workavailable](#workavailable)|
|4|[stopnotifyblocks](#stopnotifyblocks)|Cancel registered notifications for whenever a block is connected or disconnected from the main (best) chain. |None|
|5|[stopnotifywork](#stopnotifywork)|Cancel registered notifications for whenever a block is available to be mined. |None|
|6|[notifyreceived](#notifyreceived)|Send notifications when a txout spends to an address.|[recvtx](#recvtx) and [redeemingtx](#redeemingtx)|
|7|[stopnotifyreceived](#stopnotifyreceived)|Cancel registered notifications for when a txout spends to any of the passed addresses.|None|
|8|[notifyspent](#notifyspent)|Send notification when a txout is spent.|[redeemingtx](#redeemingtx)|
|9|[stopnotifyspent](#stopnotifyspent)|Cancel registered spending notifications for each passed outpoint.|None|
|10|[loadtxfilter](#loadtxfilter)|Load, add to, or reload a websocket client's transaction filter for mempool transactions, new blocks and rescanblocks.|[relevanttxaccepted](#relevanttxaccepted)|
|11|[rescan](#rescan)|Rescan block chain for transactions to addresses and spent transaction outpoints.|[recvtx](#recvtx), [redeemingtx](#redeemingtx), [rescanprogress](#rescanprogress), and [rescanfinished](#rescanfinished) |
|12|[notifynewtransactions](#notifynewtransactions)|Send notifications for all new transactions as they are accepted into the mempool.|[txaccepted](#txaccepted) or [txacceptedverbose](#txacceptedverbose)|
|13|[stopnotifynewtransactions](#stopnotifynewtransactions)|Stop sending either a txaccepted or a txacceptedverbose notification when a new transaction is accepted into the mempool.|None|
|14|[session](#session)|Return details regarding a websocket client's current connection.|None|
<a name="WSExtMethodDetails" />

**6.2 Method Details**<br />
Expand Down Expand Up @@ -730,6 +732,19 @@ user. Click the method name for further details such as parameter and return in
|Returns|Nothing|
[Return to Overview](#WSMethodOverview)<br />

***

<a name="notifywork"/>

| | |
|---|---|
|Method|notifywork|
|Notifications|[workavailable](#workavailable)|
|Parameters|None|
|Description|Request notifications for whenever a block is available to be mined.|
|Returns|Nothing|
[Return to Overview](#WSMethodOverview)<br />

***
<a name="stopnotifyblocks"/>

Expand All @@ -742,6 +757,18 @@ user. Click the method name for further details such as parameter and return in
|Returns|Nothing|
[Return to Overview](#WSMethodOverview)<br />

***
<a name="stopnotifywork"/>

| | |
|---|---|
|Method|stopnotifywork|
|Notifications|None|
|Parameters|None|
|Description|Cancel sending notifications for whenever a block is available to be mined.|
|Returns|Nothing|
[Return to Overview](#WSMethodOverview)<br />

***

<a name="notifyreceived"/>
Expand Down
17 changes: 16 additions & 1 deletion mempool/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1166,14 +1166,29 @@ func (mp *TxPool) maybeAcceptTransaction(tx *dcrutil.Tx, isNew, rateLimit, allow
mp.addTransaction(utxoView, tx, txType, bestHeight, txFee)

// If it's an SSGen (vote), insert it into the list of
// votes.
// votes and send block template generation message.
if txType == stake.TxTypeSSGen {
mp.votesMtx.Lock()
err := mp.insertVote(tx)
mp.votesMtx.Unlock()
if err != nil {
return nil, err
}

// send block template generation message here.

// currently can not because the mempool does not have a reference
// to the dcrd server or the block manager. Looking for an elegant way
// of exposing the template channel to the mempool for this.

// So far passing a reference of the template channel to the mempool
// seems to be the way to go. That's posible since the mempool and
// the block manager are initialized when the dcrd server is being
// created. Let me know if I'm overthinking this, thanks.
}

if txType != stake.TxTypeSSGen {
// send block template generation message here.
}

log.Debugf("Accepted transaction %v (pool size: %v)", txHash,
Expand Down
8 changes: 8 additions & 0 deletions rpcclient/infrastructure.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,14 @@ func (c *Client) reregisterNtfns() error {
}
}

// Reregister notifywork if needed.
if stateCopy.notifyWork {
log.Debugf("Reregistering [notifywork]")
if err := c.NotifyWork(); err != nil {
return err
}
}

// Reregister notifywinningtickets if needed.
if stateCopy.notifyWinningTickets {
log.Debugf("Reregistering [notifywinningtickets]")
Expand Down
Loading

0 comments on commit ce7b740

Please sign in to comment.