mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
101 lines
3.6 KiB
Go
101 lines
3.6 KiB
Go
package rpchandlers
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/app/appmessage"
|
|
"github.com/kaspanet/kaspad/app/rpc/rpccontext"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
|
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
|
)
|
|
|
|
// HandleGetBlocks handles the respectively named RPC command
|
|
func HandleGetBlocks(context *rpccontext.Context, _ *router.Router, request appmessage.Message) (appmessage.Message, error) {
|
|
getBlocksRequest := request.(*appmessage.GetBlocksRequestMessage)
|
|
|
|
// Validate that user didn't set IncludeTransactions without setting IncludeBlocks
|
|
if !getBlocksRequest.IncludeBlocks && getBlocksRequest.IncludeTransactions {
|
|
return &appmessage.GetBlocksResponseMessage{
|
|
Error: appmessage.RPCErrorf(
|
|
"If includeTransactions is set, then includeBlockVerboseData must be set as well"),
|
|
}, nil
|
|
}
|
|
|
|
// Decode lowHash
|
|
// If lowHash is empty - use genesis instead.
|
|
lowHash := context.Config.ActiveNetParams.GenesisHash
|
|
if getBlocksRequest.LowHash != "" {
|
|
var err error
|
|
lowHash, err = externalapi.NewDomainHashFromString(getBlocksRequest.LowHash)
|
|
if err != nil {
|
|
return &appmessage.GetBlocksResponseMessage{
|
|
Error: appmessage.RPCErrorf("Could not decode lowHash %s: %s", getBlocksRequest.LowHash, err),
|
|
}, nil
|
|
}
|
|
|
|
blockInfo, err := context.Domain.Consensus().GetBlockInfo(lowHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !blockInfo.HasHeader() {
|
|
return &appmessage.GetBlocksResponseMessage{
|
|
Error: appmessage.RPCErrorf("Could not find lowHash %s", getBlocksRequest.LowHash),
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
// Get hashes between lowHash and virtualSelectedParent
|
|
virtualSelectedParent, err := context.Domain.Consensus().GetVirtualSelectedParent()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// We use +1 because lowHash is also returned
|
|
// maxBlocks MUST be >= MergeSetSizeLimit + 1
|
|
maxBlocks := context.Config.NetParams().MergeSetSizeLimit + 1
|
|
blockHashes, highHash, err := context.Domain.Consensus().GetHashesBetween(lowHash, virtualSelectedParent, maxBlocks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// prepend low hash to make it inclusive
|
|
blockHashes = append([]*externalapi.DomainHash{lowHash}, blockHashes...)
|
|
|
|
// If the high hash is equal to virtualSelectedParent it means GetHashesBetween didn't skip any hashes, and
|
|
// there's space to add the virtualSelectedParent's anticone, otherwise you can't add the anticone because
|
|
// there's no guarantee that all of the anticone root ancestors will be present.
|
|
if highHash.Equal(virtualSelectedParent) {
|
|
virtualSelectedParentAnticone, err := context.Domain.Consensus().Anticone(virtualSelectedParent)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
blockHashes = append(blockHashes, virtualSelectedParentAnticone...)
|
|
}
|
|
|
|
// Prepare the response
|
|
response := appmessage.NewGetBlocksResponseMessage()
|
|
response.BlockHashes = hashes.ToStrings(blockHashes)
|
|
if getBlocksRequest.IncludeBlocks {
|
|
rpcBlocks := make([]*appmessage.RPCBlock, len(blockHashes))
|
|
for i, blockHash := range blockHashes {
|
|
block, err := context.Domain.Consensus().GetBlockEvenIfHeaderOnly(blockHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if getBlocksRequest.IncludeTransactions {
|
|
rpcBlocks[i] = appmessage.DomainBlockToRPCBlock(block)
|
|
} else {
|
|
rpcBlocks[i] = appmessage.DomainBlockToRPCBlock(&externalapi.DomainBlock{Header: block.Header})
|
|
}
|
|
err = context.PopulateBlockWithVerboseData(rpcBlocks[i], block.Header, nil, getBlocksRequest.IncludeTransactions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
response.Blocks = rpcBlocks
|
|
}
|
|
|
|
return response, nil
|
|
}
|