Optimize, prepare for eventual sendheaders use, add sanity check
This commit is contained in:
parent
0a8de495cc
commit
4d82af7f8e
3 changed files with 108 additions and 30 deletions
|
@ -131,6 +131,7 @@ type blockManager struct {
|
||||||
reorgList *list.List
|
reorgList *list.List
|
||||||
startHeader *list.Element
|
startHeader *list.Element
|
||||||
nextCheckpoint *chaincfg.Checkpoint
|
nextCheckpoint *chaincfg.Checkpoint
|
||||||
|
lastRequested chainhash.Hash
|
||||||
|
|
||||||
minRetargetTimespan int64 // target timespan / adjustment factor
|
minRetargetTimespan int64 // target timespan / adjustment factor
|
||||||
maxRetargetTimespan int64 // target timespan * adjustment factor
|
maxRetargetTimespan int64 // target timespan * adjustment factor
|
||||||
|
@ -604,19 +605,31 @@ func (b *blockManager) handleInvMsg(imsg *invMsg) {
|
||||||
// If this is the sync peer or we're current, get the headers
|
// If this is the sync peer or we're current, get the headers
|
||||||
// for the announced blocks and update the last announced block.
|
// for the announced blocks and update the last announced block.
|
||||||
if lastBlock != -1 && (imsg.peer == b.syncPeer || b.current()) {
|
if lastBlock != -1 && (imsg.peer == b.syncPeer || b.current()) {
|
||||||
// Make a locator starting from the latest known header we've
|
|
||||||
// processed.
|
|
||||||
locator := make(blockchain.BlockLocator, 0,
|
|
||||||
wire.MaxBlockLocatorsPerMsg)
|
|
||||||
lastHash := b.headerList.Back().Value.(*headerNode).header.BlockHash()
|
lastHash := b.headerList.Back().Value.(*headerNode).header.BlockHash()
|
||||||
locator = append(locator, &lastHash)
|
// Only send getheaders if we don't already know about the last
|
||||||
// Add locator from the database as backup.
|
// block hash being announced.
|
||||||
knownLocator, err := b.server.LatestBlockLocator()
|
if lastHash != invVects[lastBlock].Hash &&
|
||||||
if err == nil {
|
b.lastRequested != invVects[lastBlock].Hash {
|
||||||
locator = append(locator, knownLocator...)
|
// Make a locator starting from the latest known header
|
||||||
|
// we've processed.
|
||||||
|
locator := make(blockchain.BlockLocator, 0,
|
||||||
|
wire.MaxBlockLocatorsPerMsg)
|
||||||
|
locator = append(locator, &lastHash)
|
||||||
|
// Add locator from the database as backup.
|
||||||
|
knownLocator, err := b.server.LatestBlockLocator()
|
||||||
|
if err == nil {
|
||||||
|
locator = append(locator, knownLocator...)
|
||||||
|
}
|
||||||
|
// Get headers based on locator.
|
||||||
|
err = imsg.peer.PushGetHeadersMsg(locator,
|
||||||
|
&invVects[lastBlock].Hash)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Failed to send getheaders message "+
|
||||||
|
"to peer %s: %s", imsg.peer.Addr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.lastRequested = invVects[lastBlock].Hash
|
||||||
}
|
}
|
||||||
// Get headers based on locator.
|
|
||||||
imsg.peer.PushGetHeadersMsg(locator, &invVects[lastBlock].Hash)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,6 +729,12 @@ func (b *blockManager) handleHeadersMsg(hmsg *headersMsg) {
|
||||||
if hmsg.peer != b.syncPeer && !b.current() {
|
if hmsg.peer != b.syncPeer && !b.current() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Check if this is the last block we know of. This is
|
||||||
|
// a shortcut for sendheaders so that each redundant
|
||||||
|
// header doesn't cause a disk read.
|
||||||
|
if blockHash == prevHash {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// Check if this block is known. If so, we continue to
|
// Check if this block is known. If so, we continue to
|
||||||
// the next one.
|
// the next one.
|
||||||
_, _, err := b.server.GetBlockByHash(blockHash)
|
_, _, err := b.server.GetBlockByHash(blockHash)
|
||||||
|
@ -764,7 +783,7 @@ func (b *blockManager) handleHeadersMsg(hmsg *headersMsg) {
|
||||||
height: int32(backHeight),
|
height: int32(backHeight),
|
||||||
})
|
})
|
||||||
totalWork := big.NewInt(0)
|
totalWork := big.NewInt(0)
|
||||||
for _, reorgHeader := range msg.Headers[i:] {
|
for j, reorgHeader := range msg.Headers[i:] {
|
||||||
err = b.checkHeaderSanity(reorgHeader,
|
err = b.checkHeaderSanity(reorgHeader,
|
||||||
maxTimestamp, true)
|
maxTimestamp, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -776,6 +795,10 @@ func (b *blockManager) handleHeadersMsg(hmsg *headersMsg) {
|
||||||
}
|
}
|
||||||
totalWork.Add(totalWork,
|
totalWork.Add(totalWork,
|
||||||
blockchain.CalcWork(reorgHeader.Bits))
|
blockchain.CalcWork(reorgHeader.Bits))
|
||||||
|
b.reorgList.PushBack(&headerNode{
|
||||||
|
header: reorgHeader,
|
||||||
|
height: int32(backHeight+1) + int32(j),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
log.Tracef("Sane reorg attempted. Total work from "+
|
log.Tracef("Sane reorg attempted. Total work from "+
|
||||||
"reorg chain: %v", totalWork)
|
"reorg chain: %v", totalWork)
|
||||||
|
@ -808,13 +831,18 @@ func (b *blockManager) handleHeadersMsg(hmsg *headersMsg) {
|
||||||
log.Tracef("Total work from known chain: %v", knownWork)
|
log.Tracef("Total work from known chain: %v", knownWork)
|
||||||
// Compare the two work totals and reject the new chain
|
// Compare the two work totals and reject the new chain
|
||||||
// if it doesn't have more work than the previously
|
// if it doesn't have more work than the previously
|
||||||
// known chain.
|
// known chain. Disconnect if it's actually less than
|
||||||
if knownWork.Cmp(totalWork) >= 0 {
|
// the known chain.
|
||||||
log.Warnf("Reorg attempt that does not have "+
|
switch knownWork.Cmp(totalWork) {
|
||||||
"more work than known chain from peer "+
|
case 1:
|
||||||
"%s -- disconnecting", hmsg.peer.Addr())
|
log.Warnf("Reorg attempt that has less work "+
|
||||||
|
"than known chain from peer %s -- "+
|
||||||
|
"disconnecting", hmsg.peer.Addr())
|
||||||
hmsg.peer.Disconnect()
|
hmsg.peer.Disconnect()
|
||||||
|
fallthrough
|
||||||
|
case 0:
|
||||||
return
|
return
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
// At this point, we have a valid reorg, so we roll
|
// At this point, we have a valid reorg, so we roll
|
||||||
// back the existing chain and add the new block header.
|
// back the existing chain and add the new block header.
|
||||||
|
@ -884,18 +912,20 @@ func (b *blockManager) handleHeadersMsg(hmsg *headersMsg) {
|
||||||
//return
|
//return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request the next batch of headers starting from the latest known
|
// If not current, request the next batch of headers starting from the
|
||||||
// header and ending with the next checkpoint.
|
// latest known header and ending with the next checkpoint.
|
||||||
locator := blockchain.BlockLocator([]*chainhash.Hash{finalHash})
|
if !b.current() {
|
||||||
nextHash := zeroHash
|
locator := blockchain.BlockLocator([]*chainhash.Hash{finalHash})
|
||||||
if b.nextCheckpoint != nil {
|
nextHash := zeroHash
|
||||||
nextHash = *b.nextCheckpoint.Hash
|
if b.nextCheckpoint != nil {
|
||||||
}
|
nextHash = *b.nextCheckpoint.Hash
|
||||||
err := hmsg.peer.PushGetHeadersMsg(locator, &nextHash)
|
}
|
||||||
if err != nil {
|
err := hmsg.peer.PushGetHeadersMsg(locator, &nextHash)
|
||||||
log.Warnf("Failed to send getheaders message to "+
|
if err != nil {
|
||||||
"peer %s: %s", hmsg.peer.Addr(), err)
|
log.Warnf("Failed to send getheaders message to "+
|
||||||
return
|
"peer %s: %s", hmsg.peer.Addr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,36 @@ func LatestBlock(tx walletdb.Tx) (wire.BlockHeader, uint32, error) {
|
||||||
return header, height, nil
|
return header, height, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckConnectivity cycles through all of the block headers, from last to
|
||||||
|
// first, and makes sure they all connect to each other.
|
||||||
|
func CheckConnectivity(tx walletdb.Tx) error {
|
||||||
|
header, height, err := LatestBlock(tx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Couldn't retrieve latest block: %s", err)
|
||||||
|
}
|
||||||
|
for height > 0 {
|
||||||
|
newheader, newheight, err := GetBlockByHash(tx,
|
||||||
|
header.PrevBlock)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Couldn't retrieve block %s: %s",
|
||||||
|
header.PrevBlock, err)
|
||||||
|
}
|
||||||
|
if newheader.BlockHash() != header.PrevBlock {
|
||||||
|
return fmt.Errorf("Block %s doesn't match block %s's "+
|
||||||
|
"PrevBlock (%s)", newheader.BlockHash(),
|
||||||
|
header.BlockHash(), header.PrevBlock)
|
||||||
|
}
|
||||||
|
if newheight != height-1 {
|
||||||
|
return fmt.Errorf("Block %s doesn't have correct "+
|
||||||
|
"height: want %d, got %d",
|
||||||
|
newheader.BlockHash(), height-1, newheight)
|
||||||
|
}
|
||||||
|
header = newheader
|
||||||
|
height = newheight
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// BlockLocatorFromHash returns a block locator based on the provided hash.
|
// BlockLocatorFromHash returns a block locator based on the provided hash.
|
||||||
func BlockLocatorFromHash(tx walletdb.Tx, hash chainhash.Hash) blockchain.BlockLocator {
|
func BlockLocatorFromHash(tx walletdb.Tx, hash chainhash.Hash) blockchain.BlockLocator {
|
||||||
locator := make(blockchain.BlockLocator, 0, wire.MaxBlockLocatorsPerMsg)
|
locator := make(blockchain.BlockLocator, 0, wire.MaxBlockLocatorsPerMsg)
|
||||||
|
|
|
@ -212,6 +212,23 @@ func (sp *serverPeer) pushGetCFHeadersMsg(locator blockchain.BlockLocator,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pushSendHeadersMsg sends a sendheaders message to the connected peer.
|
||||||
|
func (sp *serverPeer) pushSendHeadersMsg() error {
|
||||||
|
if sp.VersionKnown() {
|
||||||
|
if sp.ProtocolVersion() > wire.SendHeadersVersion {
|
||||||
|
sp.QueueMessage(wire.NewMsgSendHeaders(), nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnVerAck is invoked when a peer receives a verack bitcoin message and is used
|
||||||
|
// to send the "sendheaders" command to peers that are of a sufficienty new
|
||||||
|
// protocol version.
|
||||||
|
func (sp *serverPeer) OnVerAck(_ *peer.Peer, msg *wire.MsgVerAck) {
|
||||||
|
sp.pushSendHeadersMsg()
|
||||||
|
}
|
||||||
|
|
||||||
// OnVersion is invoked when a peer receives a version bitcoin message
|
// OnVersion is invoked when a peer receives a version bitcoin message
|
||||||
// and is used to negotiate the protocol version details as well as kick start
|
// and is used to negotiate the protocol version details as well as kick start
|
||||||
// the communications.
|
// the communications.
|
||||||
|
@ -1057,7 +1074,8 @@ func (s *ChainService) AnnounceNewTransactions( /*newTxs []*mempool.TxDesc*/ ) {
|
||||||
func newPeerConfig(sp *serverPeer) *peer.Config {
|
func newPeerConfig(sp *serverPeer) *peer.Config {
|
||||||
return &peer.Config{
|
return &peer.Config{
|
||||||
Listeners: peer.MessageListeners{
|
Listeners: peer.MessageListeners{
|
||||||
OnVersion: sp.OnVersion,
|
OnVersion: sp.OnVersion,
|
||||||
|
//OnVerAck: sp.OnVerAck, // Don't use sendheaders yet
|
||||||
OnBlock: sp.OnBlock,
|
OnBlock: sp.OnBlock,
|
||||||
OnInv: sp.OnInv,
|
OnInv: sp.OnInv,
|
||||||
OnHeaders: sp.OnHeaders,
|
OnHeaders: sp.OnHeaders,
|
||||||
|
|
Loading…
Reference in a new issue