mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-10 16:16:47 +00:00
[DEV-332] Create partial block message in wire and make sure partial nodes receive partial blocks (#170)
* [DEV-332] Added MerkleProof to MsgBlock and rejected full-node/partial-block type misbehaviors. * [DEV-332] Fixed merge issues. * [DEV-332] Got rid of MerkleProof. Turns out we no longer need it. * [DEV-332] Got rid of NTBlockDisconnected, as no one was ever triggering it. (It was part of reorg) * [DEV-332] Implemented clearing out the payloads of transactions of outgoing blocks for partial nodes. * [DEV-332] Extracted ConvertToPartial to its own method. Added a test. Added a condition for converting to a partial block. * [DEV-332] Fixed bad ConvertToPartial condition.
This commit is contained in:
parent
b963c0d364
commit
349e62fcd5
@ -25,18 +25,13 @@ const (
|
||||
// NTBlockConnected indicates the associated block was connected to the
|
||||
// main chain.
|
||||
NTBlockConnected
|
||||
|
||||
// NTBlockDisconnected indicates the associated block was disconnected
|
||||
// from the main chain.
|
||||
NTBlockDisconnected
|
||||
)
|
||||
|
||||
// notificationTypeStrings is a map of notification types back to their constant
|
||||
// names for pretty printing.
|
||||
var notificationTypeStrings = map[NotificationType]string{
|
||||
NTBlockAccepted: "NTBlockAccepted",
|
||||
NTBlockConnected: "NTBlockConnected",
|
||||
NTBlockDisconnected: "NTBlockDisconnected",
|
||||
NTBlockAccepted: "NTBlockAccepted",
|
||||
NTBlockConnected: "NTBlockConnected",
|
||||
}
|
||||
|
||||
// String returns the NotificationType in human-readable form.
|
||||
|
@ -1210,32 +1210,6 @@ func (sm *SyncManager) handleBlockDAGNotification(notification *blockdag.Notific
|
||||
mempool.DefaultEstimateFeeMinRegisteredBlocks)
|
||||
}
|
||||
}
|
||||
|
||||
// A block has been disconnected from the block DAG.
|
||||
case blockdag.NTBlockDisconnected:
|
||||
block, ok := notification.Data.(*util.Block)
|
||||
if !ok {
|
||||
log.Warnf("Chain disconnected notification is not a block.")
|
||||
break
|
||||
}
|
||||
|
||||
// Reinsert all of the transactions (except the coinbase) into
|
||||
// the transaction pool.
|
||||
for _, tx := range block.Transactions()[1:] {
|
||||
_, _, err := sm.txMemPool.MaybeAcceptTransaction(tx,
|
||||
false, false)
|
||||
if err != nil {
|
||||
// Remove the transaction and all transactions
|
||||
// that depend on it if it wasn't accepted into
|
||||
// the transaction pool.
|
||||
sm.txMemPool.RemoveTransaction(tx, true, true)
|
||||
}
|
||||
}
|
||||
|
||||
// Rollback previous block recorded by the fee estimator.
|
||||
if sm.feeEstimator != nil {
|
||||
sm.feeEstimator.Rollback(block.Hash())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,7 +661,7 @@ func (sp *Peer) OnGetData(_ *peer.Peer, msg *wire.MsgGetData) {
|
||||
// OnGetBlocks is invoked when a peer receives a getblocks bitcoin
|
||||
// message.
|
||||
func (sp *Peer) OnGetBlocks(_ *peer.Peer, msg *wire.MsgGetBlocks) {
|
||||
// Find the most recent known block in the best chain based on the block
|
||||
// Find the most recent known block in the dag based on the block
|
||||
// locator and fetch all of the block hashes after it until either
|
||||
// wire.MaxBlocksPerMsg have been fetched or the provided stop hash is
|
||||
// encountered.
|
||||
@ -671,8 +671,8 @@ func (sp *Peer) OnGetBlocks(_ *peer.Peer, msg *wire.MsgGetBlocks) {
|
||||
// over with the genesis block if unknown block locators are provided.
|
||||
//
|
||||
// This mirrors the behavior in the reference implementation.
|
||||
chain := sp.server.DAG
|
||||
hashList := chain.LocateBlocks(msg.BlockLocatorHashes, &msg.HashStop,
|
||||
dag := sp.server.DAG
|
||||
hashList := dag.LocateBlocks(msg.BlockLocatorHashes, &msg.HashStop,
|
||||
wire.MaxBlocksPerMsg)
|
||||
|
||||
// Generate inventory message.
|
||||
@ -1286,6 +1286,16 @@ func (s *Server) pushBlockMsg(sp *Peer, hash *daghash.Hash, doneChan chan<- stru
|
||||
return err
|
||||
}
|
||||
|
||||
// If we are a full node and the peer is a partial node, we must convert
|
||||
// the block to a partial block.
|
||||
nodeSubnetworkID := s.DAG.SubnetworkID()
|
||||
peerSubnetworkID := sp.Peer.SubnetworkID()
|
||||
isNodeFull := nodeSubnetworkID.IsEqual(&wire.SubnetworkIDSupportsAll)
|
||||
isPeerFull := peerSubnetworkID.IsEqual(&wire.SubnetworkIDSupportsAll)
|
||||
if isNodeFull && !isPeerFull {
|
||||
msgBlock.ConvertToPartial(peerSubnetworkID)
|
||||
}
|
||||
|
||||
// Once we have fetched data wait for any previous operation to finish.
|
||||
if waitChan != nil {
|
||||
<-waitChan
|
||||
|
@ -4300,16 +4300,6 @@ func (s *Server) handleBlockchainNotification(notification *blockdag.Notificatio
|
||||
|
||||
// Notify registered websocket clients of incoming block.
|
||||
s.ntfnMgr.NotifyBlockConnected(block)
|
||||
|
||||
case blockdag.NTBlockDisconnected:
|
||||
block, ok := notification.Data.(*util.Block)
|
||||
if !ok {
|
||||
log.Warnf("Chain disconnected notification is not a block.")
|
||||
break
|
||||
}
|
||||
|
||||
// Notify registered websocket clients.
|
||||
s.ntfnMgr.NotifyBlockDisconnected(block)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ package wire
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/daglabs/btcd/util/subnetworkid"
|
||||
"io"
|
||||
|
||||
"github.com/daglabs/btcd/dagconfig/daghash"
|
||||
@ -231,6 +232,17 @@ func (msg *MsgBlock) BlockHash() daghash.Hash {
|
||||
return msg.Header.BlockHash()
|
||||
}
|
||||
|
||||
// ConvertToPartial clears out all the payloads of the subnetworks that are
|
||||
// incompatible with the given subnetwork ID.
|
||||
// Note: this operation modifies the block in place.
|
||||
func (msg *MsgBlock) ConvertToPartial(subnetworkID *subnetworkid.SubnetworkID) {
|
||||
for _, tx := range msg.Transactions {
|
||||
if !tx.SubnetworkID.IsEqual(subnetworkID) {
|
||||
tx.Payload = []byte{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewMsgBlock returns a new bitcoin block message that conforms to the
|
||||
// Message interface. See MsgBlock for details.
|
||||
func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock {
|
||||
|
@ -6,6 +6,7 @@ package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/daglabs/btcd/util/subnetworkid"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
@ -86,6 +87,64 @@ func TestBlockHash(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToPartial(t *testing.T) {
|
||||
transactions := []struct {
|
||||
subnetworkID subnetworkid.SubnetworkID
|
||||
payload []byte
|
||||
expectedPayloadLength int
|
||||
}{
|
||||
{
|
||||
subnetworkID: SubnetworkIDNative,
|
||||
payload: []byte{},
|
||||
expectedPayloadLength: 0,
|
||||
},
|
||||
{
|
||||
subnetworkID: SubnetworkIDRegistry,
|
||||
payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
|
||||
expectedPayloadLength: 0,
|
||||
},
|
||||
{
|
||||
subnetworkID: subnetworkid.SubnetworkID{123},
|
||||
payload: []byte{0x01},
|
||||
expectedPayloadLength: 1,
|
||||
},
|
||||
{
|
||||
subnetworkID: subnetworkid.SubnetworkID{234},
|
||||
payload: []byte{0x02},
|
||||
expectedPayloadLength: 0,
|
||||
},
|
||||
}
|
||||
|
||||
block := MsgBlock{}
|
||||
for _, transaction := range transactions {
|
||||
block.Transactions = append(block.Transactions, &MsgTx{
|
||||
SubnetworkID: transaction.subnetworkID,
|
||||
Payload: []byte{1},
|
||||
})
|
||||
}
|
||||
|
||||
block.ConvertToPartial(&subnetworkid.SubnetworkID{123})
|
||||
|
||||
for _, transaction := range transactions {
|
||||
var subnetworkTx *MsgTx
|
||||
for _, tx := range block.Transactions {
|
||||
if tx.SubnetworkID.IsEqual(&transaction.subnetworkID) {
|
||||
subnetworkTx = tx
|
||||
}
|
||||
}
|
||||
if subnetworkTx == nil {
|
||||
t.Errorf("ConvertToPartial: subnetworkID '%s' not found in block!", transaction.subnetworkID)
|
||||
continue
|
||||
}
|
||||
|
||||
payloadLength := len(subnetworkTx.Payload)
|
||||
if payloadLength != transaction.expectedPayloadLength {
|
||||
t.Errorf("ConvertToPartial: unexpected payload length for subnetwork '%s': expected: %d, got: %d",
|
||||
transaction.subnetworkID, transaction.expectedPayloadLength, payloadLength)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestBlockWire tests the MsgBlock wire encode and decode for various numbers
|
||||
// of transaction inputs and outputs and protocol versions.
|
||||
func TestBlockWire(t *testing.T) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user