├── .gitignore ├── dependency.sh ├── model.go ├── Mapreduce.sh ├── config.json ├── offchaindata.go ├── couchdb.go ├── blockreader.go ├── README.md └── eventlistener.go /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | offchaindata 3 | go.mod 4 | go.sum 5 | -------------------------------------------------------------------------------- /dependency.sh: -------------------------------------------------------------------------------- 1 | go mod init 2 | go get github.com/hyperledger/fabric@v1.3.0 3 | go get github.com/hyperledger/fabric-sdk-go@v1.0.0-beta1 4 | go get github.com/willf/bitset@v1.1.11 5 | go mod vendor -------------------------------------------------------------------------------- /model.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type SampleUser struct { 4 | 5 | Email string `json:"email"` 6 | Name string `json:"name"` 7 | Age string `json:"age"` 8 | Country string `json:"country"` 9 | } 10 | -------------------------------------------------------------------------------- /Mapreduce.sh: -------------------------------------------------------------------------------- 1 | ## Create MapReduce for Email 2 | curl -X PUT http://127.0.0.1:5990/offchaindb/_design/emailviewdesign/ -d '{"views":{"emailview":{"map":"function(doc) { emit(doc.email,1);}", "reduce":"function (keys, values, combine) {return sum(values)}"}}}' -H 'Content-Type:application/json' 3 | 4 | ## Query Reduce 5 | curl -X GET http://127.0.0.1:5990/offchaindb/_design/emailviewdesign/_view/emailview?reduce=true 6 | 7 | ## Query Group 8 | curl -X GET http://127.0.0.1:5990/offchaindb/_design/emailviewdesign/_view/emailview?group=true 9 | 10 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "peer_config_path": "exampleledger/fixtures/crypto-config/peerOrganizations/", 3 | "msp_id": "Org1MSP", 4 | "msp_type": "bccsp", 5 | "msp_config_dir": "org1.example.ledger.com/users/Admin@org1.example.ledger.com/msp", 6 | "client_key": "org1.example.ledger.com/peers/peer0.org1.example.ledger.com/tls/server.key", 7 | "client_cert": "org1.example.ledger.com/peers/peer0.org1.example.ledger.com/tls/server.crt", 8 | "root_cert": "org1.example.ledger.com/peers/peer0.org1.example.ledger.com/tls/ca.crt", 9 | "server": "peer0.org1.example.ledger.com:7051", 10 | "channel_id": "exampleledger", 11 | "config_file": "configtx" 12 | } 13 | -------------------------------------------------------------------------------- /offchaindata.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main(){ 8 | 9 | fmt.Println("************************************************") 10 | fmt.Println(" Hyperledger Fabric OffChain Storage Demo ") 11 | fmt.Println("************************************************") 12 | 13 | 14 | clientConfig, err := InitClientConfigs() 15 | if err != nil { 16 | fmt.Println("Error when initializing Client Config "+ err.Error()) 17 | return 18 | } 19 | 20 | 21 | grpcClient, err := InitGRPCClient(clientConfig) 22 | if err != nil { 23 | fmt.Println(" Error when initializing GRPC Client Connection "+err.Error()) 24 | return 25 | } 26 | 27 | err = grpcClient.InitDeliveryClient() 28 | if err != nil { 29 | fmt.Println(" Error when intializing Delivery Client "+err.Error()) 30 | return 31 | } 32 | 33 | err = grpcClient.CreateEventStream() 34 | if err != nil { 35 | fmt.Println(" Error when Creating Event Stream - "+err.Error()) 36 | return 37 | } 38 | 39 | err = grpcClient.ReadEventStream() 40 | if err != nil { 41 | fmt.Println(" Error reading event stream - "+err.Error()) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /couchdb.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "context" 6 | "encoding/json" 7 | kivik "github.com/go-kivik/kivik/v4" 8 | _ "github.com/go-kivik/couchdb/v4" 9 | "github.com/pkg/errors" 10 | ) 11 | 12 | func SaveToCouchDB(kvWriteSet []byte) error{ 13 | 14 | dbName := "offchaindb" 15 | couchdbUrl := "http://localhost:5990/" 16 | 17 | fmt.Println("\n Saving the Block details to CouchDB") 18 | fmt.Println(" CouchDB URL = ", couchdbUrl) 19 | fmt.Println(" DB Name = ", dbName) 20 | 21 | client, err := kivik.New("couch", couchdbUrl) 22 | if err != nil { 23 | fmt.Println("failed to set couchdb - "+err.Error()) 24 | return errors.WithMessage(err,"failed to set couchdb: ") 25 | } 26 | 27 | db := client.DB(dbName) 28 | 29 | User := &SampleUser{} 30 | err = json.Unmarshal(kvWriteSet, User) 31 | if err != nil{ 32 | return errors.WithMessage(err,"unmarshaling write set error: ") 33 | } 34 | 35 | fmt.Println("\n Collection Key ", User.Email) 36 | 37 | rev, err := db.Put(context.TODO(), User.Email, User) 38 | if err != nil { 39 | fmt.Println(" Error during insertion - "+err.Error()) 40 | } else { 41 | fmt.Println(" User Inserted into CouchDB - Revision = "+rev+" \n") 42 | } 43 | 44 | fmt.Println(" ######################################################################## \n") 45 | 46 | return nil 47 | } -------------------------------------------------------------------------------- /blockreader.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hyperledger/fabric/protos/common" 6 | "github.com/hyperledger/fabric/protos/peer" 7 | "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset" 8 | "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/ledger/rwset" 9 | "github.com/golang/protobuf/proto" 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | func ReadBlock(block *common.Block) error{ 14 | 15 | fmt.Println("\n ######################################################################## ") 16 | 17 | blockHeader := block.Header 18 | blockData := block.Data.Data 19 | 20 | fmt.Println(" Received Block Number = ", blockHeader.Number) 21 | 22 | //First Get the Envelope from the BlockData 23 | envelope, err := GetEnvelopeFromBlock(blockData[0]) 24 | if err != nil { 25 | return errors.WithMessage(err,"unmarshaling Envelope error: ") 26 | } 27 | 28 | //Retrieve the Payload from the Envelope 29 | payload := &common.Payload{} 30 | err = proto.Unmarshal(envelope.Payload, payload) 31 | if err != nil { 32 | return errors.WithMessage(err,"unmarshaling Payload error: ") 33 | } 34 | 35 | transaction := &peer.Transaction{} 36 | err = proto.Unmarshal(payload.Data, transaction) 37 | if err != nil { 38 | return errors.WithMessage(err,"unmarshaling Payload Transaction error: ") 39 | } 40 | 41 | chaincodeActionPayload := &peer.ChaincodeActionPayload{} 42 | err = proto.Unmarshal(transaction.Actions[0].Payload, chaincodeActionPayload) 43 | if err != nil { 44 | return errors.WithMessage(err,"unmarshaling Chaincode Action Payload error: ") 45 | } 46 | 47 | chaincodeProposalPayload := &peer.ChaincodeProposalPayload{} 48 | err = proto.Unmarshal(chaincodeActionPayload.ChaincodeProposalPayload, chaincodeProposalPayload) 49 | if err != nil { 50 | return errors.WithMessage(err,"unmarshaling Chaincode Proposal Payload error: ") 51 | } 52 | 53 | // The Input field is marshalled object of ChaincodeInvocationSpec 54 | input := &peer.ChaincodeInvocationSpec{} 55 | err = proto.Unmarshal(chaincodeProposalPayload.Input, input) 56 | if err != nil { 57 | return errors.WithMessage(err,"unmarshaling Chaincode Proposal Payload Input error: ") 58 | } 59 | 60 | chaincodeArgs := make([]string, len(input.ChaincodeSpec.Input.Args)) 61 | for i, c := range input.ChaincodeSpec.Input.Args { 62 | args := CToGoString(c[:]) 63 | chaincodeArgs[i] = args 64 | } 65 | 66 | fmt.Println("\n ## Chaincode ") 67 | fmt.Println(" Name : ", input.ChaincodeSpec.ChaincodeId.Name) 68 | fmt.Println(" Version : ", input.ChaincodeSpec.ChaincodeId.Version) 69 | fmt.Println(" Args : ", chaincodeArgs) 70 | 71 | 72 | proposalResponsePayload := &peer.ProposalResponsePayload{} 73 | err = proto.Unmarshal(chaincodeActionPayload.Action.ProposalResponsePayload, proposalResponsePayload) 74 | if err != nil { 75 | return errors.WithMessage(err,"unmarshaling Proposal Response Payload error: ") 76 | } 77 | 78 | chaincodeAction := &peer.ChaincodeAction{} 79 | err = proto.Unmarshal(proposalResponsePayload.Extension, chaincodeAction) 80 | if err != nil { 81 | return errors.WithMessage(err,"unmarshaling Extension error: ") 82 | } 83 | 84 | txReadWriteSet := &rwset.TxReadWriteSet{} 85 | err = proto.Unmarshal(chaincodeAction.Results, txReadWriteSet) 86 | if err != nil { 87 | return errors.WithMessage(err,"unmarshaling txReadWriteSet error: ") 88 | } 89 | 90 | RwSet := txReadWriteSet.NsRwset[0].Rwset 91 | 92 | kvrwset := &kvrwset.KVRWSet{} 93 | err = proto.Unmarshal(RwSet, kvrwset) 94 | if err != nil { 95 | return errors.WithMessage(err,"unmarshaling kvrwset error: ") 96 | } 97 | 98 | fmt.Println("\n Block Read Write Set ") 99 | if len(kvrwset.Reads) != 0 { 100 | fmt.Println("\n ## KVRead Set ") 101 | fmt.Println(" BlockNum = ",kvrwset.Reads[0].Version.BlockNum) 102 | fmt.Println(" TxNum = ",kvrwset.Reads[0].Version.TxNum) 103 | fmt.Println(" Key = ",kvrwset.Reads[0].Key) 104 | } 105 | 106 | if len(kvrwset.Writes) != 0 { 107 | 108 | values := CToGoString(kvrwset.Writes[0].Value[:]) 109 | 110 | fmt.Println("\n ## KVWrite Set") 111 | fmt.Println(" Key = ",kvrwset.Writes[0].Key) 112 | fmt.Println(" Value = ",values) 113 | 114 | err = SaveToCouchDB(kvrwset.Writes[0].Value) 115 | if err != nil { 116 | return errors.WithMessage(err,"error while saving to CouchDB") 117 | } 118 | } 119 | 120 | 121 | 122 | return nil 123 | 124 | } 125 | 126 | func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error){ 127 | 128 | var err error 129 | env := &common.Envelope{} 130 | if err = proto.Unmarshal(data, env); err != nil { 131 | return nil, errors.Wrap(err, "error unmarshaling Envelope") 132 | } 133 | 134 | return env, nil 135 | } 136 | 137 | func CToGoString(c []byte) string { 138 | n := -1 139 | for i, b := range c { 140 | if b == 0 { 141 | break 142 | } 143 | n = i 144 | } 145 | return string(c[:n+1]) 146 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

OffChain Data

2 |

GitHub last commit GitHub language count GitHub top language

3 |

N|Solid

4 |

OffChain Data is a sample demonstration to understand the concept of implementing offchain storage and it's capability in Hyperledger fabric Blockchain network. 5 | So, this project will work as a peer block event listener and will store the block details in the CouchDB that can be query through MapReduce.

6 |

Medium writeup : https://medium.com/@deeptiman/offchain-storage-in-hyperledger-fabric-77e28bd99e0c 7 | 8 | 9 |

Configuration requirements

10 |

You need to add the certain project details in `config.json`, so that it will be used to create an event listener and the Blocks will be received through GRPC delivery 11 | client.

12 | 13 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````` 14 | export FABRIC_CFG_PATH= /home/user/go/src/github.com/exampleledger/fixtures 15 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````` 16 | 17 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````` 18 | { 19 | "peer_config_path": "exampleledger/fixtures/crypto-config/peerOrganizations/", 20 | "msp_id": "Org1MSP", 21 | "msp_type": "bccsp", 22 | "msp_config_dir": "org1.example.ledger.com/users/Admin@org1.example.ledger.com/msp", 23 | "client_key": "org1.example.ledger.com/peers/peer0.org1.example.ledger.com/tls/server.key", 24 | "client_cert": "org1.example.ledger.com/peers/peer0.org1.example.ledger.com/tls/server.crt", 25 | "root_cert": "org1.example.ledger.com/peers/peer0.org1.example.ledger.com/tls/ca.crt", 26 | "server": "peer0.org1.example.ledger.com:7051", 27 | "channel_id": "exampleledger", 28 | "config_file": "configtx" 29 | } 30 | ````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 31 | 32 |

Create CouchDB local instance

33 | 34 | The CouchDB local instance can be created using Docker. 35 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 36 | docker run --publish 5990:5984 --detach --name offchaindb hyperledger/fabric-couchdb 37 | docker start offchaindb 38 | ````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 39 | 40 |

Mock Chaincode Model

41 | I have followed a sample user model to create the offchaindb. You can also create your own chaincode model and the offchaindata 42 | will listen the `KVWriteSet` to store in the couchdb. 43 | 44 | Sample Model 45 | `````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 46 | type SampleUser struct { 47 | Email string `json:"email"` 48 | Name string `json:"name"` 49 | Age string `json:"age"` 50 | Country string `json:"country"` 51 | } 52 | `````````````````````````````````````````````````````````````````````````````````````````````````````````````````` 53 | 54 |

Configure MapReduce

55 | 56 |

MapReduce will query the offchain data from CouchDB. So, you need to configure MapReduce for certain design element from CouchDB collection.

57 | 58 | Configure MapReduce for Email 59 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````` 60 | curl -X PUT http://127.0.0.1:5990/offchaindb/_design/emailviewdesign/ -d '{"views":{"emailview":{"map":"function(doc) { emit(doc.email,1);}", "reduce":"function (keys, values, combine) {return sum(values)}"}}}' -H 'Content-Type:application/json' 61 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````` 62 | Output 63 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````` 64 | {"ok": true, "id":"_design/emailviewdesign", "rev": "1-f34147f686003ff5c7da5a5e7e2759b8"} 65 | ```````````````````````````````````````````````````````````````````````````````````````````````````````````````` 66 | 67 | Query `Reduce` function to count total email 68 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 69 | curl -X GET http://127.0.0.1:5990/offchaindb/_design/emailviewdesign/_view/emailview?reduce=true 70 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 71 | Output 72 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 73 | {"rows":[ 74 | {"key":null,"value":7} 75 | ]} 76 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 77 | 78 | Query `Map` function to list all emails 79 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 80 | curl -X GET http://127.0.0.1:5990/offchaindb/_design/emailviewdesign/_view/emailview?group=true 81 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 82 | Output 83 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 84 | {"rows":[ 85 | {"key":"alice@gmail.com","value":1}, 86 | {"key":"john@gmail.com","value":1}, 87 | {"key":"michale@gmail.com","value":1}, 88 | {"key":"mark@mail.com","value":1}, 89 | {"key":"bob@gmail.com","value":1}, 90 | {"key":"oscar@gmail.com","value":1}, 91 | {"key":"william@example.com","value":1} 92 | ]} 93 | ``````````````````````````````````````````````````````````````````````````````````````````````````````````````` 94 | 95 | So, all the query peformed in offchain without querying from blockchain ledger. 96 | 97 |

License

98 |

This project is licensed under the MIT License

99 | -------------------------------------------------------------------------------- /eventlistener.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "time" 7 | "math" 8 | "context" 9 | "io/ioutil" 10 | "encoding/json" 11 | "google.golang.org/grpc" 12 | "github.com/pkg/errors" 13 | "github.com/hyperledger/fabric/common/util" 14 | "github.com/hyperledger/fabric/common/crypto" 15 | "github.com/hyperledger/fabric/common/localmsp" 16 | "github.com/hyperledger/fabric/protos/peer" 17 | "github.com/hyperledger/fabric/protos/orderer" 18 | common2 "github.com/hyperledger/fabric/peer/common" 19 | "github.com/hyperledger/fabric/protos/common" 20 | "github.com/hyperledger/fabric/protos/utils" 21 | "github.com/hyperledger/fabric/core/comm" 22 | ) 23 | 24 | type DeliveryClient interface { 25 | Send(*common.Envelope) error 26 | Recv() (*peer.DeliverResponse, error) 27 | } 28 | 29 | type GRPCClient struct { 30 | grpcClient *comm.GRPCClient 31 | grpcClientConn *grpc.ClientConn 32 | deliveryClient DeliveryClient 33 | signer crypto.LocalSigner 34 | tlsCertHash []byte 35 | } 36 | 37 | var ( 38 | fabric_cfg_path string 39 | msp_id string 40 | msp_type string 41 | msp_config_dir string 42 | client_key string 43 | client_cert string 44 | root_cert string 45 | server string 46 | channel_id string 47 | config_file string 48 | ) 49 | 50 | func InitClientConfigs() (comm.ClientConfig,error) { 51 | 52 | err := ReadConfigs() 53 | if err != nil { 54 | return comm.ClientConfig{}, errors.WithMessage(err, "failed to read config json") 55 | } 56 | 57 | /* Initialize Config */ 58 | err = common2.InitConfig(config_file) 59 | if err != nil { 60 | return comm.ClientConfig{}, errors.WithMessage(err, "fatal error when initializing config") 61 | } 62 | 63 | /* Initialize Crypto */ 64 | err = common2.InitCrypto(msp_config_dir, msp_id, msp_type) 65 | if err != nil { 66 | return comm.ClientConfig{}, errors.WithMessage(err, "Cannot run client because") 67 | } 68 | 69 | /* Init Client Configs */ 70 | clientConfig := comm.ClientConfig{ 71 | KaOpts: comm.DefaultKeepaliveOptions, 72 | SecOpts: &comm.SecureOptions{}, 73 | Timeout: 5 * time.Minute, 74 | } 75 | 76 | clientConfig.SecOpts.UseTLS = true 77 | clientConfig.SecOpts.RequireClientCert = true 78 | 79 | rootCert, err := ioutil.ReadFile(root_cert) 80 | if err != nil { 81 | return comm.ClientConfig{}, errors.WithMessage(err, "Error loading TLS root certificate") 82 | } 83 | clientConfig.SecOpts.ServerRootCAs = [][]byte{rootCert} 84 | 85 | 86 | clientKey, err := ioutil.ReadFile(client_key) 87 | if err != nil { 88 | return comm.ClientConfig{}, errors.WithMessage(err, "Error loading client TLS key") 89 | } 90 | clientConfig.SecOpts.Key = clientKey 91 | 92 | clientCert, err := ioutil.ReadFile(client_cert) 93 | if err != nil { 94 | return comm.ClientConfig{}, errors.WithMessage(err, "Error loading client TLS cert") 95 | } 96 | clientConfig.SecOpts.Certificate = clientCert 97 | 98 | 99 | fmt.Println(" Crypto & Client Configs initialized Successfully!") 100 | 101 | return clientConfig, nil 102 | } 103 | 104 | 105 | func InitGRPCClient(clientConfig comm.ClientConfig) (*GRPCClient, error){ 106 | 107 | grpcClient, err := comm.NewGRPCClient(clientConfig) 108 | if err != nil { 109 | fmt.Println("Error creating grpc client: "+ err.Error()) 110 | return nil, errors.WithMessage(err, "Error creating grpc client") 111 | } 112 | 113 | grpcClientConn, err := grpcClient.NewConnection(server, "") 114 | if err != nil { 115 | fmt.Println("Error connecting: "+ err.Error()) 116 | return nil, errors.WithMessage(err, "Error connecting") 117 | } 118 | 119 | signer := localmsp.NewSigner() 120 | tlsCertHash := util.ComputeSHA256(grpcClient.Certificate().Certificate[0]) 121 | 122 | fmt.Println(" GRPC Client initialized Successfully!") 123 | 124 | return &GRPCClient { 125 | grpcClient: grpcClient, 126 | grpcClientConn: grpcClientConn, 127 | signer: signer, 128 | tlsCertHash: tlsCertHash, 129 | }, nil 130 | } 131 | 132 | 133 | func(grpc *GRPCClient) InitDeliveryClient() (error){ 134 | 135 | deliverClient := peer.NewDeliverClient(grpc.grpcClientConn) 136 | if deliverClient == nil { 137 | return errors.New("No Host Available") 138 | } 139 | 140 | var err error 141 | var deliveryClient DeliveryClient 142 | 143 | deliveryClient, err = deliverClient.Deliver(context.Background()) 144 | if err != nil { 145 | return errors.WithMessage(err, "failed to connect") 146 | } 147 | 148 | grpc.deliveryClient = deliveryClient 149 | 150 | fmt.Println(" GRPC Delivery Client initialized Successfully!") 151 | 152 | return nil 153 | } 154 | 155 | func(grpc *GRPCClient) CreateEventStream() error{ 156 | 157 | envelope, err := grpc.CreateSignedEnvelope() 158 | if err != nil { 159 | return errors.WithMessage(err, "Error creating signed envelope") 160 | } 161 | 162 | err = grpc.deliveryClient.Send(envelope) 163 | if err != nil { 164 | return errors.WithMessage(err, "Error in delivering the signed envelope") 165 | } 166 | fmt.Println(" GRPC Event Stream created Successfully!") 167 | return nil 168 | } 169 | 170 | func(grpc *GRPCClient) CreateSignedEnvelope() (*common.Envelope,error) { 171 | 172 | start := &orderer.SeekPosition{ 173 | Type: &orderer.SeekPosition_Newest{ 174 | Newest: &orderer.SeekNewest{}, 175 | }, 176 | } 177 | 178 | stop := &orderer.SeekPosition{ 179 | Type: &orderer.SeekPosition_Specified{ 180 | Specified: &orderer.SeekSpecified{ 181 | Number: math.MaxUint64, 182 | }, 183 | }, 184 | } 185 | 186 | env, err := utils.CreateSignedEnvelopeWithTLSBinding(common.HeaderType_DELIVER_SEEK_INFO, 187 | channel_id, grpc.signer, 188 | &orderer.SeekInfo{ 189 | Start: start, 190 | Stop: stop, 191 | Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY, 192 | }, 0, 0, grpc.tlsCertHash) 193 | if err != nil { 194 | return nil, errors.WithMessage(err, "Error creating signed envelope") 195 | } 196 | 197 | fmt.Println(" Signed Envelope Created ") 198 | fmt.Println(" Seek Info Start = ", start) 199 | fmt.Println(" Seek Info Stop = ", stop) 200 | 201 | return env, nil 202 | } 203 | 204 | 205 | func(grpc *GRPCClient) ReadEventStream() error{ 206 | 207 | fmt.Println(" \n Started listening GRPC Event Stream at ", server) 208 | 209 | for { 210 | 211 | receivedMsg, err := grpc.deliveryClient.Recv() 212 | if err != nil { 213 | return errors.WithMessage(err, "Error in Receiving Message") 214 | } 215 | 216 | switch t := receivedMsg.Type.(type) { 217 | 218 | case *peer.DeliverResponse_Status: 219 | fmt.Println(" Received DeliverResponse Status = ", t) 220 | case *peer.DeliverResponse_Block: 221 | fmt.Println(" Received a new Block from = ",channel_id) 222 | ReadBlock(t.Block) 223 | 224 | } 225 | } 226 | 227 | return nil 228 | } 229 | 230 | 231 | 232 | func ReadConfigs() error { 233 | 234 | ROOT := os.Getenv("GOPATH") 235 | 236 | configFile, err := os.Open("config.json") 237 | if err != nil { 238 | return errors.WithMessage(err, "failed to read config json") 239 | } 240 | defer configFile.Close() 241 | 242 | 243 | byteValue, _ := ioutil.ReadAll(configFile) 244 | var configs map[string]interface{} 245 | json.Unmarshal([]byte(byteValue), &configs) 246 | 247 | //peer_config_path := ROOT + fmt.Sprint(configs["peer_config_path"]) 248 | msp_id = fmt.Sprint(configs["msp_id"]) 249 | msp_type = fmt.Sprint(configs["msp_type"]) 250 | msp_config_dir = fabric_cfg_path + fmt.Sprint(configs["msp_config_dir"]) 251 | client_key = fabric_cfg_path + fmt.Sprint(configs["client_key"]) 252 | client_cert = fabric_cfg_path + fmt.Sprint(configs["client_cert"]) 253 | root_cert = fabric_cfg_path + fmt.Sprint(configs["root_cert"]) 254 | server = fmt.Sprint(configs["server"]) 255 | channel_id = fmt.Sprint(configs["channel_id"]) 256 | config_file = fmt.Sprint(configs["config_file"]) 257 | 258 | fmt.Println(" ### Configs ") 259 | fmt.Println(" ROOT = ", ROOT) 260 | fmt.Println(" PEER_CONFIG_PATH = ",configs["peer_config_path"]) 261 | fmt.Println(" MSP ID = ",configs["msp_id"]) 262 | fmt.Println(" MSP TYPE = ",configs["msp_type"]) 263 | fmt.Println(" MSP CONFIG DIR = ",configs["msp_config_dir"]) 264 | fmt.Println(" CLIENT KEY = ",configs["client_key"]) 265 | fmt.Println(" CLIENT CERT = ",configs["client_cert"]) 266 | fmt.Println(" ROOT CERT = ",configs["root_cert"]) 267 | fmt.Println(" GRPC LISTENING SERVER = ",configs["server"]) 268 | fmt.Println(" CHANNEL ID = ",configs["channel_id"]) 269 | fmt.Println(" CONFIG FILE = ",configs["config_file"]) 270 | 271 | return nil 272 | } 273 | --------------------------------------------------------------------------------