// Copyright IBM Corp. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package main import ( "context" "flag" "fmt" "math" "os" "github.com/hyperledger/fabric-config/protolator" cb "github.com/hyperledger/fabric-protos-go/common" ab "github.com/hyperledger/fabric-protos-go/orderer" "github.com/hyperledger/fabric/bccsp/factory" "github.com/hyperledger/fabric/internal/pkg/identity" "github.com/hyperledger/fabric/msp" mspmgmt "github.com/hyperledger/fabric/msp/mgmt" "github.com/hyperledger/fabric/orderer/common/localconfig" "github.com/hyperledger/fabric/protoutil" "google.golang.org/grpc" ) var ( oldest = &ab.SeekPosition{Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}}} newest = &ab.SeekPosition{Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}}} maxStop = &ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: math.MaxUint64}}} ) type deliverClient struct { client ab.AtomicBroadcast_DeliverClient channelID string signer identity.SignerSerializer quiet bool } func newDeliverClient(client ab.AtomicBroadcast_DeliverClient, channelID string, signer identity.SignerSerializer, quiet bool) *deliverClient { return &deliverClient{client: client, channelID: channelID, signer: signer, quiet: quiet} } func (r *deliverClient) seekHelper(start *ab.SeekPosition, stop *ab.SeekPosition) *cb.Envelope { env, err := protoutil.CreateSignedEnvelope(cb.HeaderType_DELIVER_SEEK_INFO, r.channelID, r.signer, &ab.SeekInfo{ Start: start, Stop: stop, Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, }, 0, 0) if err != nil { panic(err) } return env } func (r *deliverClient) seekOldest() error { return r.client.Send(r.seekHelper(oldest, maxStop)) } func (r *deliverClient) seekNewest() error { return r.client.Send(r.seekHelper(newest, maxStop)) } func (r *deliverClient) seekSingle(blockNumber uint64) error { specific := &ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: blockNumber}}} return r.client.Send(r.seekHelper(specific, specific)) } func (r *deliverClient) readUntilClose() { for { msg, err := r.client.Recv() if err != nil { fmt.Println("Error receiving:", err) return } switch t := msg.Type.(type) { case *ab.DeliverResponse_Status: fmt.Println("Got status ", t) return case *ab.DeliverResponse_Block: if !r.quiet { fmt.Println("Received block: ") err := protolator.DeepMarshalJSON(os.Stdout, t.Block) if err != nil { fmt.Printf(" Error pretty printing block: %s", err) } } else { fmt.Println("Received block: ", t.Block.Header.Number) } } } } func main() { conf, err := localconfig.Load() if err != nil { fmt.Println("failed to load config:", err) os.Exit(1) } // Load local MSP mspConfig, err := msp.GetLocalMspConfig(conf.General.LocalMSPDir, conf.General.BCCSP, conf.General.LocalMSPID) if err != nil { fmt.Println("Failed to load MSP config:", err) os.Exit(0) } err = mspmgmt.GetLocalMSP(factory.GetDefault()).Setup(mspConfig) if err != nil { // Handle errors reading the config file fmt.Println("Failed to initialize local MSP:", err) os.Exit(0) } signer, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetDefaultSigningIdentity() if err != nil { fmt.Println("Failed to load local signing identity:", err) os.Exit(0) } var channelID string var serverAddr string var seek int var quiet bool flag.StringVar(&serverAddr, "server", fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort), "The RPC server to connect to.") flag.StringVar(&channelID, "channelID", "mychannel", "The channel ID to deliver from.") flag.BoolVar(&quiet, "quiet", false, "Only print the block number, will not attempt to print its block contents.") flag.IntVar(&seek, "seek", -2, "Specify the range of requested blocks."+ "Acceptable values:"+ "-2 (or -1) to start from oldest (or newest) and keep at it indefinitely."+ "N >= 0 to fetch block N only.") flag.Parse() if seek < -2 { fmt.Println("Wrong seek value.") flag.PrintDefaults() } conn, err := grpc.Dial(serverAddr, grpc.WithInsecure()) if err != nil { fmt.Println("Error connecting:", err) return } client, err := ab.NewAtomicBroadcastClient(conn).Deliver(context.TODO()) if err != nil { fmt.Println("Error connecting:", err) return } s := newDeliverClient(client, channelID, signer, quiet) switch seek { case -2: err = s.seekOldest() case -1: err = s.seekNewest() default: err = s.seekSingle(uint64(seek)) } if err != nil { fmt.Println("Received error:", err) } s.readUntilClose() }