You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: main.go
    path of file: ./repos/storj/cmd/tools/is-valid-sj1-blob
    
    the code of the file until where you have to start completion: // Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/base32"
	"encoding/binary"
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/zeebo/blake3"

	"storj.io/common/pb"
	"storj.io/common/storj"
	"storj.io/storj/storagenode/pieces"
)

var (
	doFindCorrectLength = flag.Bool("find-length", false,
		"If set, when a file with invalid length is detected, try to determine the correct length by evaluating "+
			"the hash after every byte. This may be slow.")
)

const (
	v1PieceHeaderFramingSize = 2
	// Rather than look up all the details of how a signature digest is encoded with its salt and how big a salt can be,
	// I'll establish some too-loose bounds based purely on observation.
	minSignatureSize = sha256.Size
	maxSignatureSize = 80
)

var (
	wayTooEarly = time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC)
	wayTooLate  = time.Now().AddDate(0, 0, 1)

	pathEncoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").WithPadding(base32.NoPadding)
)

func readBlobHeader(r io.Reader) (*pb.PieceHeader, error) {
	var headerBytes [pieces.V1PieceHeaderReservedArea]byte
	framingBytes := headerBytes[:v1PieceHeaderFramingSize]
	n, err := io.ReadFull(r, framingBytes)
	if err != nil {
		return nil, err
	}
	if n != v1PieceHeaderFramingSize {
		return nil, errors.New("could not read whole PieceHeader framing f
    
func checkSanity(header *pb.PieceHeader, fileSize int64) error {
	var expectHashSize int
	switch header.HashAlgorithm {
	case pb.PieceHashAlgorithm_SHA256:
		expectHashSize = sha256.Size
	case pb.PieceHashAlgorithm_BLAKE3:
		expectHashSize = blake3.New().Size()
	default:
		return fmt.Errorf("invalid PieceHashAlgorithm %d", header.HashAlgorithm)
	}
	sig := header.Signature
	if len(sig) < minSignatureSize || len(sig) > maxSignatureSize {
		return fmt.Errorf("signature field has invalid size %d", len(sig))
	}
	sig2 := header.OrderLimit.SatelliteSignature
	if len(sig2) < minSignatureSize || len(sig2) > maxSignatureSize {
		return fmt.Errorf("satellite signature field has invalid size %d", len(sig2))
	}
	if header.OrderLimit.Limit < (fileSize - int64(pieces.V1PieceHeaderReservedArea)) {
		return fmt.Errorf("order limit size %d is too small for file size %d", header.OrderLimit.Limit, fileSize)
	}
	if len(header.Hash) != expectHashSize {
		return fmt.Errorf("hash field should be %d bytes, but is %d bytes", expectHashSize, len(header.Hash))
	}
	if header.OrderLimit.OrderCreation.Before(wayTooEarly) {
		return fmt.Errorf("order creation field has improbably early value %s", header.OrderLimit.OrderCreation.String())
	}
	if header.OrderLimit.OrderCreation.After(wayTooLate) {
		return fmt.Errorf("order creation field has improbably late value %s", header.OrderLimit.OrderCreation.String())
	}
	switch header.OrderLimit.Action {
	case pb.PieceAction_PUT, pb.PieceAction_GET, pb.PieceAction_GET_AUDIT, pb.PieceAction_GET_REPAIR, pb.PieceAction_PUT_REPAIR, pb.PieceAction_DELETE, pb.PieceAction_PUT_GRACEFUL_EXIT:
	default:
		return fmt.Errorf("order limit action has invalid value %d", header.OrderLimit.Action)
	}
	return nil
}