mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-10-14 00:59:33 +00:00
Disallow header only blocks on RPC, relay and when requesting IBD full blocks (#1537)
This commit is contained in:
parent
19878aa062
commit
d2f4ed660c
@ -2,6 +2,7 @@ package flowcontext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@ -98,6 +99,10 @@ func (f *FlowContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks
|
|||||||
|
|
||||||
// AddBlock adds the given block to the DAG and propagates it.
|
// AddBlock adds the given block to the DAG and propagates it.
|
||||||
func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
|
||||||
|
if len(block.Transactions) == 0 {
|
||||||
|
return protocolerrors.Errorf(false, "cannot add header only block")
|
||||||
|
}
|
||||||
|
|
||||||
blockInsertionResult, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
|
blockInsertionResult, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||||
|
@ -104,6 +104,11 @@ func (flow *handleRelayInvsFlow) start() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = flow.banIfBlockIsHeaderOnly(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
log.Debugf("Processing block %s", inv.Hash)
|
log.Debugf("Processing block %s", inv.Hash)
|
||||||
missingParents, blockInsertionResult, err := flow.processBlock(block)
|
missingParents, blockInsertionResult, err := flow.processBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -140,6 +145,15 @@ func (flow *handleRelayInvsFlow) start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (flow *handleRelayInvsFlow) banIfBlockIsHeaderOnly(block *externalapi.DomainBlock) error {
|
||||||
|
if len(block.Transactions) == 0 {
|
||||||
|
return protocolerrors.Errorf(true, "sent header of %s block where expected block with body",
|
||||||
|
consensushashing.BlockHash(block))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) {
|
func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) {
|
||||||
if len(flow.invsQueue) > 0 {
|
if len(flow.invsQueue) > 0 {
|
||||||
var inv *appmessage.MsgInvRelayBlock
|
var inv *appmessage.MsgInvRelayBlock
|
||||||
|
@ -533,6 +533,11 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do
|
|||||||
return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash)
|
return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = flow.banIfBlockIsHeaderOnly(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
blockInsertionResult, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
if errors.Is(err, ruleerrors.ErrDuplicateBlock) {
|
||||||
|
@ -24,6 +24,19 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var headerOnlyBlock = &externalapi.DomainBlock{
|
||||||
|
Header: blockheader.NewImmutableBlockHeader(
|
||||||
|
constants.MaxBlockVersion,
|
||||||
|
[]*externalapi.DomainHash{externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})},
|
||||||
|
&externalapi.DomainHash{},
|
||||||
|
&externalapi.DomainHash{},
|
||||||
|
&externalapi.DomainHash{},
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
var orphanBlock = &externalapi.DomainBlock{
|
var orphanBlock = &externalapi.DomainBlock{
|
||||||
Header: blockheader.NewImmutableBlockHeader(
|
Header: blockheader.NewImmutableBlockHeader(
|
||||||
constants.MaxBlockVersion,
|
constants.MaxBlockVersion,
|
||||||
@ -35,6 +48,7 @@ var orphanBlock = &externalapi.DomainBlock{
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
Transactions: []*externalapi.DomainTransaction{{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var validPruningPointBlock = &externalapi.DomainBlock{
|
var validPruningPointBlock = &externalapi.DomainBlock{
|
||||||
@ -48,6 +62,7 @@ var validPruningPointBlock = &externalapi.DomainBlock{
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
Transactions: []*externalapi.DomainTransaction{{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var invalidPruningPointBlock = &externalapi.DomainBlock{
|
var invalidPruningPointBlock = &externalapi.DomainBlock{
|
||||||
@ -61,6 +76,7 @@ var invalidPruningPointBlock = &externalapi.DomainBlock{
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
Transactions: []*externalapi.DomainTransaction{{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var unexpectedIBDBlock = &externalapi.DomainBlock{
|
var unexpectedIBDBlock = &externalapi.DomainBlock{
|
||||||
@ -74,6 +90,7 @@ var unexpectedIBDBlock = &externalapi.DomainBlock{
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
Transactions: []*externalapi.DomainTransaction{{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var invalidBlock = &externalapi.DomainBlock{
|
var invalidBlock = &externalapi.DomainBlock{
|
||||||
@ -87,6 +104,7 @@ var invalidBlock = &externalapi.DomainBlock{
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
Transactions: []*externalapi.DomainTransaction{{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var unknownBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})
|
var unknownBlockHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{1})
|
||||||
@ -95,6 +113,7 @@ var validPruningPointHash = consensushashing.BlockHash(validPruningPointBlock)
|
|||||||
var invalidBlockHash = consensushashing.BlockHash(invalidBlock)
|
var invalidBlockHash = consensushashing.BlockHash(invalidBlock)
|
||||||
var invalidPruningPointHash = consensushashing.BlockHash(invalidPruningPointBlock)
|
var invalidPruningPointHash = consensushashing.BlockHash(invalidPruningPointBlock)
|
||||||
var orphanBlockHash = consensushashing.BlockHash(orphanBlock)
|
var orphanBlockHash = consensushashing.BlockHash(orphanBlock)
|
||||||
|
var headerOnlyBlockHash = consensushashing.BlockHash(headerOnlyBlock)
|
||||||
|
|
||||||
type fakeRelayInvsContext struct {
|
type fakeRelayInvsContext struct {
|
||||||
testName string
|
testName string
|
||||||
@ -450,6 +469,29 @@ func TestHandleRelayInvs(t *testing.T) {
|
|||||||
expectsBan: true,
|
expectsBan: true,
|
||||||
expectsErrToContain: "got unrequested block",
|
expectsErrToContain: "got unrequested block",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "sending header only block on relay",
|
||||||
|
funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) {
|
||||||
|
err := incomingRoute.Enqueue(appmessage.NewMsgInvBlock(headerOnlyBlockHash))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Enqueue: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := outgoingRoute.DequeueWithTimeout(time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DequeueWithTimeout: %+v", err)
|
||||||
|
}
|
||||||
|
_ = msg.(*appmessage.MsgRequestRelayBlocks)
|
||||||
|
|
||||||
|
err = incomingRoute.Enqueue(appmessage.DomainBlockToMsgBlock(headerOnlyBlock))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Enqueue: %+v", err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectsProtocolError: true,
|
||||||
|
expectsBan: true,
|
||||||
|
expectsErrToContain: "block where expected block with body",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "sending invalid block",
|
name: "sending invalid block",
|
||||||
funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) {
|
funcToExecute: func(t *testing.T, incomingRoute, outgoingRoute *router.Route, context *fakeRelayInvsContext) {
|
||||||
|
@ -2,6 +2,7 @@ package rpchandlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
|
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||||
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
@ -25,9 +26,10 @@ func HandleSubmitBlock(context *rpccontext.Context, _ *router.Router, request ap
|
|||||||
|
|
||||||
err := context.ProtocolManager.AddBlock(domainBlock)
|
err := context.ProtocolManager.AddBlock(domainBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.As(err, &ruleerrors.RuleError{}) {
|
if !errors.As(err, &ruleerrors.RuleError{}) || !errors.As(err, &protocolerrors.ProtocolError{}) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &appmessage.SubmitBlockResponseMessage{
|
return &appmessage.SubmitBlockResponseMessage{
|
||||||
Error: appmessage.RPCErrorf("Block rejected. Reason: %s", err),
|
Error: appmessage.RPCErrorf("Block rejected. Reason: %s", err),
|
||||||
RejectReason: appmessage.RejectReasonBlockInvalid,
|
RejectReason: appmessage.RejectReasonBlockInvalid,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user