package rpc import ( "bufio" "bytes" "encoding/hex" "github.com/kaspanet/kaspad/rpc/model" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/util/daghash" "github.com/kaspanet/kaspad/util/subnetworkid" ) // handleGetBlock implements the getBlock command. func handleGetBlock(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*model.GetBlockCmd) // Load the raw block bytes from the database. hash, err := daghash.NewHashFromStr(c.Hash) if err != nil { return nil, rpcDecodeHexError(c.Hash) } // Return an appropriate error if the block is known to be invalid if s.dag.IsKnownInvalid(hash) { return nil, &model.RPCError{ Code: model.ErrRPCBlockInvalid, Message: "Block is known to be invalid", } } // Return an appropriate error if the block is an orphan if s.dag.IsKnownOrphan(hash) { return nil, &model.RPCError{ Code: model.ErrRPCOrphanBlock, Message: "Block is an orphan", } } block, err := s.dag.BlockByHash(hash) if err != nil { return nil, &model.RPCError{ Code: model.ErrRPCBlockNotFound, Message: "Block not found", } } blockBytes, err := block.Bytes() if err != nil { return nil, &model.RPCError{ Code: model.ErrRPCBlockInvalid, Message: "Cannot serialize block", } } // Handle partial blocks if c.Subnetwork != nil { requestSubnetworkID, err := subnetworkid.NewFromStr(*c.Subnetwork) if err != nil { return nil, &model.RPCError{ Code: model.ErrRPCInvalidRequest.Code, Message: "invalid subnetwork string", } } nodeSubnetworkID := s.cfg.SubnetworkID if requestSubnetworkID != nil { if nodeSubnetworkID != nil { if !nodeSubnetworkID.IsEqual(requestSubnetworkID) { return nil, &model.RPCError{ Code: model.ErrRPCInvalidRequest.Code, Message: "subnetwork does not match this partial node", } } // nothing to do - partial node stores partial blocks } else { // Deserialize the block. msgBlock := block.MsgBlock() msgBlock.ConvertToPartial(requestSubnetworkID) var b bytes.Buffer msgBlock.Serialize(bufio.NewWriter(&b)) blockBytes = b.Bytes() } } } // When the verbose flag is set to false, simply return the serialized block // as a hex-encoded string (verbose flag is on by default). if c.Verbose != nil && !*c.Verbose { return hex.EncodeToString(blockBytes), nil } // The verbose flag is set, so generate the JSON object and return it. // Deserialize the block. block, err = util.NewBlockFromBytes(blockBytes) if err != nil { context := "Failed to deserialize block" return nil, internalRPCError(err.Error(), context) } s.dag.RLock() defer s.dag.RUnlock() blockReply, err := buildGetBlockVerboseResult(s, block, c.VerboseTx == nil || !*c.VerboseTx) if err != nil { return nil, err } return blockReply, nil }