├── .generators ├── README.md ├── deps.go └── install.sh ├── .github └── workflows │ ├── go.yml │ └── golangci-lint.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── api ├── chaincode.go ├── channel.go ├── client.go ├── config │ ├── config.go │ ├── config_yaml.go │ └── samples │ │ ├── config.gossip_discovery.yaml │ │ └── config.local_discovery.yaml ├── discovery.go ├── orderer.go ├── peer.go ├── peer_deliver.go └── peer_pool.go ├── block ├── block.go ├── block.pb.go ├── block.pb.validate.go ├── block.proto ├── block_methods.go ├── block_test.go ├── block_write.go ├── buf.yaml ├── chan_config.go ├── chan_config.pb.go ├── chan_config.pb.validate.go ├── chan_config.proto ├── envelope.go ├── header.go ├── key.go ├── payload.go ├── proposal.go ├── seek.go ├── smartbft │ ├── common │ │ ├── common.pb.go │ │ ├── common.pb.validate.go │ │ └── common.proto │ ├── configuration.pb.go │ ├── configuration.pb.validate.go │ └── configuration.proto ├── transform │ ├── action.go │ ├── action_payload.go │ ├── args.go │ ├── event.go │ ├── kvread.go │ ├── kvwrite.go │ ├── lifecycle.go │ ├── map_prefix.go │ ├── proto.go │ └── replace_bytes.go ├── transformer.go ├── tx.go ├── tx_action.go └── txflags │ ├── validation_flags.go │ └── validation_flags_test.go ├── buf.gen.go.yaml ├── buf.gen.svc.yaml ├── buf.work.yaml ├── client ├── ca │ ├── client.go │ ├── entity.go │ ├── errors.go │ ├── http │ │ ├── affiliation.go │ │ ├── certificate.go │ │ ├── client.go │ │ ├── enroll.go │ │ ├── identity.go │ │ ├── info.go │ │ ├── opts.go │ │ ├── register.go │ │ └── revoke.go │ ├── mock │ │ ├── ca.go │ │ ├── ca_test.go │ │ └── testdata │ │ │ ├── README.md │ │ │ ├── ca-key.pem │ │ │ ├── ca.csr │ │ │ ├── ca.pem │ │ │ └── csr.json │ ├── opts.go │ ├── request.go │ └── response.go ├── chaincode │ ├── core.go │ ├── invoke_builder.go │ ├── invoke_test.go │ ├── query_builder.go │ ├── system.go │ ├── testdata │ │ ├── config.yaml │ │ └── msp │ │ │ ├── admincerts │ │ │ └── admincerts.pem │ │ │ ├── cacerts │ │ │ └── cacert.pem │ │ │ ├── keystore │ │ │ └── 018f389d200e48536367f05b99122f355ba33572009bd2b8b521cdbbb717a5b5_sk │ │ │ └── signcerts │ │ │ └── cert.pem │ ├── tw_waiter.go │ └── txwaiter │ │ ├── all.go │ │ └── self.go ├── channel.go ├── channel │ ├── interface.go │ └── list.go ├── core.go ├── core_opts.go ├── core_public.go ├── deliver │ ├── deliver.go │ ├── seek_opt.go │ ├── seek_opt_test.go │ ├── subs │ │ ├── block.go │ │ ├── chaincode.go │ │ └── tx.go │ └── testing │ │ ├── block_deliverer_mock.go │ │ └── deliver.go ├── discovery │ ├── discovery.go │ ├── discovery_dto_models.go │ ├── endpoints_mapper.go │ ├── gossip.go │ ├── gossip_discovery_service.go │ └── local.go ├── errors.go ├── errors │ ├── error.go │ └── multi.go ├── grpc │ ├── grpc.go │ ├── grpc_test.go │ ├── opencensus │ │ └── hlf │ │ │ └── hlf.go │ └── testdata │ │ └── tls │ │ ├── ca │ │ ├── ca-key.pem │ │ ├── ca.csr │ │ ├── ca.pem │ │ ├── cfssl.json │ │ └── csr.json │ │ ├── client │ │ ├── cert-key.pem │ │ ├── cert.csr │ │ ├── cert.pem │ │ └── csr.json │ │ ├── readme.md │ │ └── server │ │ ├── cert-key.pem │ │ ├── cert.csr │ │ ├── cert.pem │ │ └── csr.json ├── logger.go ├── orderer.go ├── peer.go ├── peer_pool.go └── tx │ ├── args.go │ ├── context.go │ ├── endorsement.go │ ├── id.go │ ├── proto_invoke.go │ ├── proto_query.go │ └── seek_block.go ├── cmd └── ccpackage │ ├── README.md │ └── main.go ├── crypto ├── ecdsa │ └── ecdsa.go ├── interface.go ├── random.go └── suite.go ├── examples ├── caclient │ ├── config.yaml │ └── main.go ├── cc_call │ ├── README.md │ ├── cc_call.go │ └── cfg.yaml ├── channel_info │ └── blockchanin_info.go ├── cli │ ├── README.md │ └── main.go ├── discovery_and_transaction │ ├── cfg.yaml │ └── main.go ├── event-listener │ ├── README.md │ └── main.go └── example_cc │ └── main.go ├── go.mod ├── go.sum ├── identity ├── config │ └── identity.go ├── file.go ├── identity.go ├── loader.go ├── msp.go ├── msp_opts.go ├── msp_test.go └── testdata │ ├── Org1MSPAdmin │ ├── cacerts │ │ └── localhost-7054-ca-org1.pem │ ├── config.yaml │ ├── keystore │ │ └── 4895cac2d326f796ca79f8ca7c9051c8417373012d2b5f62fb01dd9f0566fc72_sk │ ├── signcerts │ │ └── cert.pem │ └── testdata.go │ ├── Org1MSPPeer │ ├── cacerts │ │ └── localhost-7054-ca-org1.pem │ ├── config.yaml │ ├── keystore │ │ └── d9e8fe76f63667c8fdaf1bbbd222111a93c4decc866899848239b011896bee59_sk │ ├── signcerts │ │ └── cert.pem │ └── testdata.go │ └── Org1MSPPeerAndAdmin │ ├── admincerts │ └── cert.pem │ ├── cacerts │ └── localhost-7054-ca-org1.pem │ ├── config.yaml │ ├── keystore │ ├── 4895cac2d326f796ca79f8ca7c9051c8417373012d2b5f62fb01dd9f0566fc72_sk │ └── d9e8fe76f63667c8fdaf1bbbd222111a93c4decc866899848239b011896bee59_sk │ └── signcerts │ └── cert.pem ├── observer ├── README.md ├── block.go ├── channel.go ├── channel_blocks.go ├── channel_blocks_common.go ├── channel_blocks_parsed.go ├── channel_blocks_stream.go ├── channels_blocks_peer.go ├── channels_blocks_peer_common.go ├── channels_blocks_peer_common_test.go ├── channels_blocks_peer_concurrently.go ├── channels_blocks_peer_parsed.go ├── channels_blocks_peer_parsed_test.go ├── channels_matcher.go ├── old_files │ ├── event.go │ ├── event_channel.go │ ├── event_peer.go │ └── opts.go ├── peer_channels.go ├── peer_channels_fetcher_mock.go ├── peer_channels_mock.go ├── peer_channels_test.go ├── stream.go └── suite_test.go ├── service ├── ccpackage │ ├── fetcher │ │ ├── fetcher.go │ │ ├── file.go │ │ ├── file_test.go │ │ ├── gogit.go │ │ ├── nope.go │ │ └── tar.go │ ├── packages.pb.go │ ├── packages.pb.gw.go │ ├── packages.pb.validate.go │ ├── packages.proto │ ├── packages.swagger.json │ ├── packer │ │ ├── docker │ │ │ ├── container.go │ │ │ ├── packer.go │ │ │ └── tar.go │ │ └── packer.go │ └── store │ │ ├── file │ │ └── file.go │ │ ├── memory │ │ ├── memory.go │ │ └── memory_test.go │ │ └── storage.go ├── orderer │ └── channel.go ├── service.go ├── systemcc │ ├── cscc │ │ ├── cscc.go │ │ ├── cscc.pb.go │ │ ├── cscc.pb.gw.go │ │ ├── cscc.pb.validate.go │ │ ├── cscc.proto │ │ └── cscc.swagger.json │ ├── lifecycle │ │ ├── lifecycle.go │ │ ├── lifecycle.pb.go │ │ ├── lifecycle.pb.gw.go │ │ ├── lifecycle.pb.validate.go │ │ ├── lifecycle.proto │ │ └── lifecycle.swagger.json │ ├── lscc │ │ ├── lscc.go │ │ ├── lscc.pb.go │ │ ├── lscc.pb.gw.go │ │ ├── lscc.pb.validate.go │ │ ├── lscc.proto │ │ └── lscc.swagger.json │ └── qscc │ │ ├── qscc.go │ │ ├── qscc.pb.go │ │ ├── qscc.pb.gw.go │ │ ├── qscc.pb.validate.go │ │ ├── qscc.proto │ │ └── qscc.swagger.json └── wallet │ ├── store.go │ ├── store │ ├── file │ │ └── store.go │ ├── memory │ │ └── store.go │ └── vault │ │ ├── store.go │ │ └── store_test.go │ ├── wallet.go │ ├── wallet.pb.go │ ├── wallet.pb.gw.go │ ├── wallet.pb.validate.go │ ├── wallet.proto │ └── wallet.swagger.json ├── testdata ├── blocks │ ├── blocks.go │ └── fixtures │ │ ├── fabcar-channel │ │ ├── 0.pb │ │ ├── 1.pb │ │ ├── 10.pb │ │ ├── 11.pb │ │ ├── 2.pb │ │ ├── 3.pb │ │ ├── 4.pb │ │ ├── 5.pb │ │ ├── 6.pb │ │ ├── 7.pb │ │ ├── 8.pb │ │ └── 9.pb │ │ └── sample-channel │ │ ├── 0.pb │ │ ├── 1.pb │ │ ├── 2.pb │ │ ├── 3.pb │ │ ├── 4.pb │ │ ├── 5.pb │ │ ├── 6.pb │ │ ├── 7.pb │ │ ├── 8.pb │ │ └── 9.pb └── yac │ └── postgres-ca.crt └── third_party ├── buf.yaml ├── google ├── api │ ├── annotations.proto │ ├── http.proto │ └── httpbody.proto └── rpc │ ├── code.proto │ ├── error_details.proto │ └── status.proto ├── hyperledger └── fabric-protos │ ├── common │ ├── collection.proto │ ├── common.proto │ ├── configtx.proto │ ├── configuration.proto │ ├── ledger.proto │ └── policies.proto │ ├── discovery │ └── protocol.proto │ ├── gateway │ └── gateway.proto │ ├── gossip │ └── message.proto │ ├── ledger │ ├── queryresult │ │ └── kv_query_result.proto │ └── rwset │ │ ├── kvrwset │ │ └── kv_rwset.proto │ │ └── rwset.proto │ ├── msp │ ├── identities.proto │ ├── msp_config.proto │ └── msp_principal.proto │ ├── orderer │ ├── ab.proto │ ├── cluster.proto │ ├── configuration.proto │ ├── etcdraft │ │ ├── configuration.proto │ │ └── metadata.proto │ └── kafka.proto │ ├── peer │ ├── chaincode.proto │ ├── chaincode_event.proto │ ├── chaincode_shim.proto │ ├── collection.proto │ ├── configuration.proto │ ├── events.proto │ ├── lifecycle │ │ ├── chaincode_definition.proto │ │ ├── db.proto │ │ └── lifecycle.proto │ ├── peer.proto │ ├── policy.proto │ ├── proposal.proto │ ├── proposal_response.proto │ ├── query.proto │ ├── resources.proto │ ├── signed_cc_dep_spec.proto │ ├── snapshot.proto │ └── transaction.proto │ └── transientstore │ └── transientstore.proto └── validate └── validate.proto /.generators/README.md: -------------------------------------------------------------------------------- 1 | # Code generation 2 | 3 | HLF-SDK-GO use code generation with [Buf](https://docs.buf.build/) 4 | 5 | ## Using generators 6 | 7 | ### 1. Install Buf 8 | 9 | https://docs.buf.build/installation 10 | 11 | ### 2. Install generators 12 | 13 | With go package versions from CCKit [go.mod](../go.mod): 14 | 15 | ``` 16 | cd generators 17 | ./install.sh 18 | ``` 19 | 20 | ### 3. Run buf 21 | 22 | Generation command defined in [Makefile](../Makefile) 23 | ``` 24 | make proto 25 | ``` 26 | -------------------------------------------------------------------------------- /.generators/deps.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package generators 5 | 6 | import ( 7 | // proto/grpc 8 | _ "github.com/golang/protobuf/protoc-gen-go" 9 | 10 | // validation schema 11 | _ "github.com/envoyproxy/protoc-gen-validate" 12 | 13 | _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway" 14 | 15 | _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger" 16 | ) 17 | -------------------------------------------------------------------------------- /.generators/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | GENERATOR_DIR=$PWD 4 | 5 | VER="21.1" 6 | ARCH="aarch" 7 | unameOut="$(uname -s)" 8 | case "${unameOut}" in 9 | Linux*) OS=linux;; 10 | Darwin*) OS=osx;; 11 | *) OS="xxx" 12 | esac 13 | 14 | echo ${GENERATOR_DIR} ${OS} $VER $ARCH 15 | 16 | if [ ! -d ${GENERATOR_DIR}/bin ]; then 17 | mkdir ${GENERATOR_DIR}/bin 18 | fi 19 | if [ ! -d ${GENERATOR_DIR}/dist/protoc ]; then 20 | mkdir -p ${GENERATOR_DIR}/dist/protoc 21 | fi 22 | 23 | if [ ! -f ${GENERATOR_DIR}/dist/protoc/protoc.zip ]; then 24 | echo "download protoc https://github.com/protocolbuffers/protobuf/releases/download/v$VER/protoc-$VER-$OS-${ARCH}_64.zip" 25 | curl https://github.com/protocolbuffers/protobuf/releases/download/v$VER/protoc-$VER-$OS-${ARCH}_64.zip -o $GENERATOR_DIR/dist/protoc/protoc.zip -L 26 | fi 27 | 28 | (cd ./dist/protoc && unzip -o protoc.zip) 29 | cp -f ${GENERATOR_DIR}/dist/protoc/bin/protoc ${GENERATOR_DIR}/bin/protoc 30 | echo "installed "`${GENERATOR_DIR}/bin/protoc --version` 31 | 32 | 33 | pwd 34 | for genpkg in `go list -f '{{ join .Imports "\n" }}' deps.go` 35 | do 36 | echo "building $genpkg..." 37 | go get ${genpkg} 38 | go build -mod=readonly -o ${GENERATOR_DIR}/bin/`basename $genpkg` -trimpath ${genpkg} 39 | echo "installed $genpkg" 40 | done 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go Quality 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | test: 7 | name: Test with Coverage 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Set up Go 11 | uses: actions/setup-go@v5 12 | with: 13 | go-version: '1.22' 14 | 15 | - name: Check out code 16 | uses: actions/checkout@v4 17 | - name: Run Unit tests 18 | run: | 19 | go test -race -covermode=atomic -coverprofile=profile.cov -coverpkg=github.com/s7techlab/hlf-sdk-go/... ./client/... 20 | 21 | - name: Send coverage 22 | uses: shogo82148/actions-goveralls@v1 23 | with: 24 | path-to-profile: profile.cov 25 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | 3 | on: [ push, pull_request ] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | golangci: 10 | name: lint 11 | strategy: 12 | matrix: 13 | go: [ "1.22.x","1.23.x" ] 14 | os: [ ubuntu-latest ] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-go@v5 19 | with: 20 | go-version: ${{ matrix.go }} 21 | cache: false 22 | - name: golangci-lint 23 | uses: golangci/golangci-lint-action@v6 24 | with: 25 | # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. 26 | version: v1.63 27 | 28 | # Optional: working directory, useful for monorepos 29 | # working-directory: somedir 30 | 31 | # Optional: golangci-lint command line arguments. 32 | args: --exclude SA1019 --timeout=20m 33 | 34 | # Optional: show only new issues if it's a pull request. The default value is `false`. 35 | only-new-issues: false 36 | 37 | # Optional: if set to true then the action will use pre-installed Go 38 | # skip-go-installation: true 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | .generators/bin 4 | .generators/dist 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GOFLAGS ?= -mod=vendor 2 | 3 | PROTO_PACKAGES_GO := block 4 | PROTO_PACKAGES_SVC := service 5 | 6 | test: 7 | @echo "go test -mod vendor ./..." 8 | @go test ./... 9 | 10 | proto: clean 11 | @for pkg in $(PROTO_PACKAGES_GO) ;do echo $$pkg && buf generate --template buf.gen.go.yaml $$pkg -o ./$$(echo $$pkg | cut -d "/" -f1); done 12 | @for pkg in $(PROTO_PACKAGES_SVC) ;do echo $$pkg && buf generate --template buf.gen.svc.yaml $$pkg -o ./$$(echo $$pkg | cut -d "/" -f1); done 13 | @go fmt ./... 14 | 15 | clean: 16 | @for pkg in $(PROTO_PACKAGES_GO); do find $$pkg \( -name '*.pb.go' -or -name '*.pb.md' \) -delete;done 17 | @for pkg in $(PROTO_PACKAGES_SVC); do find $$pkg \( -name '*.pb.go' -or -name '*.pb.cc.go' -or -name '*.pb.gw.go' -or -name '*.swagger.json' -or -name '*.pb.md' \) -delete;done -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Hyperledger Fabric SDK 2 | 3 | [![Coverage Status](https://coveralls.io/repos/github/s7techlab/hlf-sdk-go/badge.svg)](https://coveralls.io/github/s7techlab/hlf-sdk-go) 4 | 5 | #### Project structure: 6 | 7 | - api - interface definitions 8 | - ca - sdk for Hyperledger Fabric CA 9 | - client - sdk for Hyperledger Fabric Network 10 | - crypto - cryptographic implementation 11 | - discovery - discovery service implementation 12 | - examples - examples of using current SDK (invoke cli and events client) 13 | - [event-listener](examples/event-listener) - example of using peer.DeliverService, which shows new blocks 14 | - [blockchain_info](examples/channel_info/blockchain_info.go) - example of viewing info about channels and channel's ledger 15 | - identity - identity implementation 16 | - proto - Hyperledger fabric protobuf messages creating and parsing -------------------------------------------------------------------------------- /api/channel.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Channel interface { 8 | // Chaincode returns chaincode instance by chaincode name 9 | Chaincode(ctx context.Context, name string) (Chaincode, error) 10 | // Join channel 11 | Join(ctx context.Context) error 12 | } 13 | 14 | // types which identify tx "wait'er" policy 15 | // we don't make it as alias for preventing binding to our lib 16 | const ( 17 | TxWaiterSelfType string = "self" 18 | TxWaiterAllType string = "all" 19 | ) 20 | -------------------------------------------------------------------------------- /api/config/config_yaml.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/pkg/errors" 7 | "gopkg.in/yaml.v2" 8 | ) 9 | 10 | func NewYamlConfig(configPath string) (*Config, error) { 11 | if configBytes, err := os.ReadFile(configPath); err != nil { 12 | return nil, errors.Wrap(err, `failed to read config file`) 13 | } else { 14 | var c Config 15 | if err = yaml.Unmarshal(configBytes, &c); err != nil { 16 | return nil, errors.Wrap(err, `failed to unmarshal yaml config`) 17 | } 18 | return &c, nil 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /api/config/samples/config.gossip_discovery.yaml: -------------------------------------------------------------------------------- 1 | discovery: 2 | type: gossip 3 | connection: 4 | host: peer0.org1.example.com:7051 5 | timeout: 5s 6 | 7 | tls_certs_map: 8 | - address: orderer.example.com:7050 9 | tls: 10 | enabled: true 11 | ca_cert_path: github.com/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt 12 | cert_path: github.com/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/signcerts/cert.pem 13 | key_path: github.com/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/keystore/ef18cb3e70e5fdf825e4a83f40243d64a8a3a824b9b0fd99cf363856f5c6c174_sk 14 | - address: peer0.org2.example.com:9051 15 | tls: 16 | enabled: true 17 | ca_cert_path: github.com/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/tlscacerts/tls-localhost-8054-ca-org2.pem 18 | cert_path: github.com/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/signcerts/cert.pem 19 | key_path: github.com/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/keystore/15ba9010b75e3869ae1ad69191d59a9951a692fbde4b9a07b8bf08fb0173b3df_sk 20 | - address: peer0.org1.example.com:7051 21 | tls: 22 | enabled: true 23 | ca_cert_path: github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/tlscacerts/tls-localhost-7054-ca-org1.pem 24 | cert_path: github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/signcerts/cert.pem 25 | key_path: github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/keystore/76d679929878afc06711d3c611af1c84dcac5be7cd6563d8338a7500b79109d9_sk -------------------------------------------------------------------------------- /api/config/samples/config.local_discovery.yaml: -------------------------------------------------------------------------------- 1 | # Orderer config 2 | orderers: 3 | - host: localhost:7050 4 | useTLS: false 5 | timeout: 5s 6 | 7 | discovery: 8 | type: local 9 | options: 10 | channels: 11 | - name: public 12 | description: public channel for all members 13 | chaincodes: 14 | - name: network 15 | type: golang 16 | version: "0.1" 17 | description: system discovery chaincode 18 | policy: "AND ('OPERATORMSP.admin')" 19 | 20 | crypto: 21 | type: ecdsa 22 | options: 23 | # Possible curves: P256, P384, P512 24 | curve: P256 25 | # Possible algorithms for signature: SHA256, SHA384, SHA512 26 | signatureAlgorithm: SHA256 27 | # Possible hashing algorithms: SHA2-256, SHA2-384, SHA3-256, SHA3-384 28 | hash: SHA2-256 29 | 30 | msp: 31 | - name: OPERATORMSP 32 | endorsers: 33 | - host: 127.0.0.1:27051 34 | grpc: 35 | retry: 36 | max: 2 37 | timeout: 1s 38 | # timeout for peer.DeliverClient 39 | deliver_timeout: 6s 40 | - host: localhost:7051 41 | grpc: 42 | retry: 43 | max: 5 44 | timeout: 2s 45 | - name: S7MSP 46 | endorsers: 47 | - host: localhost:17051 48 | - name: BANKMSP 49 | endorsers: 50 | - host: localhost:37051 -------------------------------------------------------------------------------- /api/discovery.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/s7techlab/hlf-sdk-go/api/config" 7 | ) 8 | 9 | type DiscoveryProvider interface { 10 | Chaincode(ctx context.Context, channelName string, ccName string) (ChaincodeDiscoverer, error) 11 | Channel(ctx context.Context, channelName string) (ChannelDiscoverer, error) 12 | LocalPeers(ctx context.Context) (LocalPeersDiscoverer, error) 13 | } 14 | 15 | // ChaincodeDiscoverer - looking for info about network, channel, chaincode in local configs or gossip 16 | type ChaincodeDiscoverer interface { 17 | Endorsers() []*HostEndpoint 18 | ChaincodeName() string 19 | ChaincodeVersion() string 20 | 21 | ChannelDiscoverer 22 | } 23 | 24 | // ChannelDiscoverer - info about orderers in channel 25 | type ChannelDiscoverer interface { 26 | Orderers() []*HostEndpoint 27 | ChannelName() string 28 | } 29 | 30 | // LocalPeersDiscoverer discover local peers without providing info about channel, chaincode 31 | type LocalPeersDiscoverer interface { 32 | Peers() []*HostEndpoint 33 | } 34 | 35 | type HostEndpoint struct { 36 | MspID string 37 | // each host could have own tls settings 38 | HostAddresses []*Endpoint 39 | } 40 | 41 | type Endpoint struct { 42 | Host string 43 | TlsConfig config.TlsConfig 44 | } 45 | -------------------------------------------------------------------------------- /api/orderer.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hyperledger/fabric-protos-go/common" 7 | "github.com/hyperledger/fabric-protos-go/orderer" 8 | "github.com/hyperledger/fabric/msp" 9 | ) 10 | 11 | type Orderer interface { 12 | // Broadcast sends envelope to orderer and returns it's result 13 | Broadcast(ctx context.Context, envelope *common.Envelope) (*orderer.BroadcastResponse, error) 14 | // Deliver fetches block from orderer by envelope 15 | Deliver(ctx context.Context, envelope *common.Envelope) (*common.Block, error) 16 | // GetConfigBlock returns last config block 17 | GetConfigBlock(ctx context.Context, signer msp.SigningIdentity, channelName string) (*common.Block, error) 18 | } 19 | -------------------------------------------------------------------------------- /api/peer.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hyperledger/fabric-protos-go/common" 8 | "github.com/hyperledger/fabric-protos-go/peer" 9 | "github.com/hyperledger/fabric/msp" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type Endorser interface { 14 | // Endorse sends proposal to endorsing peer and returns its result 15 | Endorse(ctx context.Context, proposal *peer.SignedProposal) (*peer.ProposalResponse, error) 16 | } 17 | 18 | type ChannelListGetter interface { 19 | GetChannels(ctx context.Context) (*peer.ChannelQueryResponse, error) 20 | } 21 | 22 | type ChainInfoGetter interface { 23 | GetChainInfo(ctx context.Context, channel string) (*common.BlockchainInfo, error) 24 | } 25 | 26 | // Peer is common interface for endorsing peer 27 | type Peer interface { 28 | Querier 29 | 30 | Endorser 31 | 32 | ChannelListGetter 33 | 34 | ChainInfoGetter 35 | 36 | BlocksDeliverer 37 | 38 | ParsedBlocksDeliverer 39 | 40 | EventsDeliverer 41 | 42 | // DeliverClient returns DeliverClient 43 | DeliverClient(identity msp.SigningIdentity) (DeliverClient, error) 44 | // URI returns url used for grpc connection 45 | URI() string 46 | // Conn returns instance of grpc connection 47 | Conn() *grpc.ClientConn 48 | // Close terminates peer connection 49 | Close() error 50 | } 51 | 52 | // PeerEndorseError describes peer endorse error 53 | // TODO currently not working cause peer embeds error in string 54 | type PeerEndorseError struct { 55 | Status int32 56 | Message string 57 | } 58 | 59 | func (e PeerEndorseError) Error() string { 60 | return fmt.Sprintf("failed to endorse: %s (code: %d)", e.Message, e.Status) 61 | } 62 | -------------------------------------------------------------------------------- /api/peer_pool.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hyperledger/fabric-protos-go/peer" 7 | "github.com/hyperledger/fabric/msp" 8 | ) 9 | 10 | type MSPPeerPool interface { 11 | Peers() []Peer 12 | FirstReadyPeer() (Peer, error) 13 | Process(ctx context.Context, proposal *peer.SignedProposal) (*peer.ProposalResponse, error) 14 | DeliverClient(identity msp.SigningIdentity) (DeliverClient, error) 15 | } 16 | 17 | type PeerPool interface { 18 | GetPeers() map[string][]Peer 19 | GetMSPPeers(mspID string) []Peer 20 | FirstReadyPeer(mspID string) (Peer, error) 21 | Add(mspId string, peer Peer, strategy PeerPoolCheckStrategy) error 22 | EndorseOnMSP(ctx context.Context, mspId string, proposal *peer.SignedProposal) (*peer.ProposalResponse, error) 23 | EndorseOnMSPs(ctx context.Context, endorsingMspIDs []string, proposal *peer.SignedProposal) ([]*peer.ProposalResponse, error) 24 | DeliverClient(mspId string, identity msp.SigningIdentity) (DeliverClient, error) 25 | Close() error 26 | } 27 | 28 | type PeerPoolCheckStrategy func(ctx context.Context, peer Peer, alive chan bool) 29 | -------------------------------------------------------------------------------- /block/block_methods.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/golang/protobuf/ptypes/timestamp" 7 | "github.com/hyperledger/fabric-protos-go/peer" 8 | ) 9 | 10 | func (x *Block) ValidEnvelopes() []*Envelope { 11 | var envs []*Envelope 12 | for _, e := range x.GetData().GetEnvelopes() { 13 | if e.ValidationCode != peer.TxValidationCode_VALID { 14 | continue 15 | } 16 | 17 | envs = append(envs, e) 18 | } 19 | 20 | return envs 21 | } 22 | 23 | func (x *Block) BlockDate() *timestamp.Timestamp { 24 | var max *timestamp.Timestamp 25 | for _, envelope := range x.ValidEnvelopes() { 26 | ts := envelope.GetPayload().GetHeader().GetChannelHeader().GetTimestamp() 27 | 28 | if ts.AsTime().After(max.AsTime()) { 29 | max = ts 30 | } 31 | } 32 | return max 33 | } 34 | 35 | // Writes ONLY VALID writes from block 36 | func (x *Block) Writes() []*Write { 37 | var blockWrites []*Write 38 | 39 | for _, e := range x.ValidEnvelopes() { 40 | for _, a := range e.TxActions() { 41 | for _, rwSet := range a.NsReadWriteSet() { 42 | for _, write := range rwSet.GetRwset().GetWrites() { 43 | blockWrite := &Write{ 44 | KWWrite: write, 45 | 46 | Block: x.GetHeader().GetNumber(), 47 | Chaincode: a.ChaincodeSpec().GetChaincodeId().GetName(), 48 | ChaincodeVersion: a.ChaincodeSpec().GetChaincodeId().GetVersion(), 49 | Tx: e.ChannelHeader().GetTxId(), 50 | Timestamp: e.ChannelHeader().GetTimestamp(), 51 | } 52 | 53 | blockWrite.KeyObjectType, blockWrite.KeyAttrs = SplitCompositeKey(write.Key) 54 | // Normalized key without null byte 55 | blockWrite.Key = strings.Join(append([]string{blockWrite.KeyObjectType}, blockWrite.KeyAttrs...), "_") 56 | 57 | blockWrites = append(blockWrites, blockWrite) 58 | } 59 | } 60 | } 61 | } 62 | 63 | return blockWrites 64 | } 65 | -------------------------------------------------------------------------------- /block/block_write.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "errors" 5 | "regexp" 6 | "strings" 7 | 8 | "github.com/golang/protobuf/ptypes/timestamp" 9 | "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 10 | ) 11 | 12 | var ( 13 | ErrEmptyKeyAttrs = errors.New(`empty key attrs`) 14 | ) 15 | 16 | type ( 17 | Write struct { 18 | KWWrite *kvrwset.KVWrite 19 | 20 | KeyObjectType string 21 | KeyAttrs []string 22 | Key string 23 | 24 | Block uint64 25 | Chaincode string 26 | ChaincodeVersion string 27 | Tx string 28 | Timestamp *timestamp.Timestamp 29 | } 30 | ) 31 | 32 | func (bw *Write) HasKeyObjectType(objectTypes ...string) bool { 33 | for _, t := range objectTypes { 34 | if bw.KeyObjectType == t { 35 | return true 36 | } 37 | } 38 | return false 39 | } 40 | 41 | func (bw *Write) HasKeyPartObjectType(objectTypes ...string) bool { 42 | for _, t := range objectTypes { 43 | if strings.Contains(bw.KeyObjectType, t) { 44 | return true 45 | } 46 | } 47 | return false 48 | } 49 | 50 | func (bw *Write) HasKeyObjectTypeRegexp(pattern string) bool { 51 | matched, _ := regexp.MatchString(pattern, bw.KeyObjectType) 52 | 53 | return matched 54 | } 55 | -------------------------------------------------------------------------------- /block/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | lint: 3 | use: 4 | - BASIC 5 | - FILE_LOWER_SNAKE_CASE 6 | - SERVICE_SUFFIX 7 | - ENUM_VALUE_PREFIX 8 | except: 9 | - PACKAGE_DIRECTORY_MATCH 10 | breaking: 11 | use: 12 | - FILE 13 | -------------------------------------------------------------------------------- /block/chan_config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hlfsdkgo.block; 4 | 5 | option go_package = "github.com/s7techlab/hlf-sdk-go/block"; 6 | 7 | import "hyperledger/fabric-protos/common/configuration.proto"; 8 | import "hyperledger/fabric-protos/common/policies.proto"; 9 | import "hyperledger/fabric-protos/msp/msp_config.proto"; 10 | import "hyperledger/fabric-protos/orderer/configuration.proto"; 11 | import "hyperledger/fabric-protos/peer/configuration.proto"; 12 | 13 | message ChannelConfig { 14 | map applications = 1; 15 | map orderers = 2; 16 | 17 | orderer.BatchSize orderer_batch_size = 3; 18 | string orderer_batch_timeout = 4; 19 | orderer.ConsensusType orderer_consensus_type = 5; 20 | 21 | string consortium = 6; 22 | string hashing_algorithm = 7; 23 | common.BlockDataHashingStructure block_data_hashing_structure = 8; 24 | common.Capabilities capabilities = 9; 25 | 26 | map policy = 10; 27 | } 28 | 29 | message MSP { 30 | string name = 1; 31 | msp.FabricMSPConfig config = 2; 32 | map policy = 3; 33 | } 34 | 35 | message ApplicationConfig { 36 | string name = 1; 37 | MSP msp = 2; 38 | repeated protos.AnchorPeer anchor_peers = 3; 39 | } 40 | 41 | message OrdererConfig { 42 | string name = 1; 43 | MSP msp = 2; 44 | repeated string endpoints = 3; 45 | } 46 | 47 | message Policy { 48 | oneof policy { 49 | common.ImplicitMetaPolicy implicit = 1; 50 | common.SignaturePolicyEnvelope signature_policy = 2; 51 | } 52 | } 53 | 54 | enum PolicyKey { 55 | POLICY_KEY_UNDEFINED = 0; 56 | POLICY_KEY_READERS = 1; 57 | POLICY_KEY_WRITERS = 2; 58 | POLICY_KEY_LIFECYCLE_ENDORSEMENT = 3; 59 | POLICY_KEY_ENDORSEMENT = 4; 60 | } 61 | 62 | message Certificate { 63 | // sha256 hash 64 | bytes fingerprint = 1; 65 | bytes data = 2; 66 | CertType type = 3; 67 | string msp_id = 4; 68 | string msp_name = 5; 69 | } 70 | 71 | enum CertType { 72 | CERT_TYPE_UNDEFINED = 0; 73 | CERT_TYPE_CA = 1; 74 | CERT_TYPE_INTERMEDIATE = 2; 75 | CERT_TYPE_ADMIN = 3; 76 | } 77 | -------------------------------------------------------------------------------- /block/key.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "unicode/utf8" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | const ( 10 | minUnicodeRuneValue = 0 //U+0000 11 | maxUnicodeRuneValue = utf8.MaxRune //U+10FFFF - maximum (and unallocated) code point 12 | compositeKeyNamespace = "\x00" 13 | //emptyKeySubstitute = "\x01" 14 | ) 15 | 16 | func validateCompositeKeyAttribute(str string) error { 17 | if !utf8.ValidString(str) { 18 | return errors.Errorf("not a valid utf8 string: [%x]", str) 19 | } 20 | for index, runeValue := range str { 21 | if runeValue == minUnicodeRuneValue || runeValue == maxUnicodeRuneValue { 22 | return errors.Errorf(`input contain unicode %#U starting at position [%d]. %#U and %#U are not allowed in the input attribute of a composite key`, 23 | runeValue, index, minUnicodeRuneValue, maxUnicodeRuneValue) 24 | } 25 | } 26 | return nil 27 | } 28 | 29 | func CreateCompositeKey(objectType string, attributes []string) (string, error) { 30 | if err := validateCompositeKeyAttribute(objectType); err != nil { 31 | return "", err 32 | } 33 | ck := compositeKeyNamespace + objectType + string(rune(minUnicodeRuneValue)) 34 | for _, att := range attributes { 35 | if err := validateCompositeKeyAttribute(att); err != nil { 36 | return "", err 37 | } 38 | ck += att + string(rune(minUnicodeRuneValue)) 39 | } 40 | return ck, nil 41 | } 42 | 43 | func SplitCompositeKey(compositeKey string) (string, []string) { 44 | componentIndex := 1 45 | var components []string 46 | for i := 1; i < len(compositeKey); i++ { 47 | if compositeKey[i] == minUnicodeRuneValue { 48 | components = append(components, compositeKey[componentIndex:i]) 49 | componentIndex = i + 1 50 | } 51 | } 52 | 53 | if componentIndex == 1 { 54 | return compositeKey, []string{} 55 | } 56 | 57 | return components[0], components[1:] 58 | } 59 | -------------------------------------------------------------------------------- /block/payload.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/golang/protobuf/proto" 7 | "github.com/hyperledger/fabric-protos-go/common" 8 | "github.com/hyperledger/fabric/msp" 9 | ) 10 | 11 | // NewMarshalledCommonPayload returns marshalled payload from headers and data 12 | func NewMarshalledCommonPayload(header *common.Header, data []byte) ([]byte, error) { 13 | return proto.Marshal(&common.Payload{ 14 | Header: header, 15 | Data: data}) 16 | } 17 | 18 | func NewCommonEnvelope(payload []byte, signer msp.SigningIdentity) (*common.Envelope, error) { 19 | payloadSignature, err := signer.Sign(payload) 20 | if err != nil { 21 | return nil, fmt.Errorf(`sign payloadl: %w`, err) 22 | } 23 | 24 | return &common.Envelope{ 25 | Payload: payload, 26 | Signature: payloadSignature, 27 | }, nil 28 | } 29 | -------------------------------------------------------------------------------- /block/proposal.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/golang/protobuf/proto" 7 | "github.com/hyperledger/fabric-protos-go/peer" 8 | "github.com/hyperledger/fabric/msp" 9 | ) 10 | 11 | func NewPeerSignedProposal(proposal []byte, identity msp.SigningIdentity) (*peer.SignedProposal, error) { 12 | signedProposal, err := identity.Sign(proposal) 13 | if err != nil { 14 | return nil, fmt.Errorf(`sign proposal: %w`, err) 15 | } 16 | 17 | return &peer.SignedProposal{ 18 | ProposalBytes: proposal, 19 | Signature: signedProposal}, nil 20 | } 21 | 22 | func NewMarshaledPeerProposal(header []byte, chaincode string, args [][]byte, transientMap map[string][]byte) ([]byte, error) { 23 | payload, err := NewMarshalledChaincodeProposalPayload(chaincode, args, transientMap) 24 | if err != nil { 25 | return nil, fmt.Errorf(`chaincode proposal payload: %w`, err) 26 | } 27 | 28 | return proto.Marshal(&peer.Proposal{ 29 | Header: header, 30 | Payload: payload, 31 | }) 32 | } 33 | 34 | func NewMarshalledChaincodeProposalPayload(chaincode string, args [][]byte, transientMap map[string][]byte) ([]byte, error) { 35 | invSpec, err := NewMarshalledPeerChaincodeInvocationSpec(chaincode, args) 36 | if err != nil { 37 | return nil, fmt.Errorf(`invocation spec: %w`, err) 38 | } 39 | 40 | return proto.Marshal(&peer.ChaincodeProposalPayload{ 41 | Input: invSpec, 42 | TransientMap: transientMap, 43 | }) 44 | } 45 | 46 | func NewMarshalledPeerChaincodeInvocationSpec(chaincode string, args [][]byte) ([]byte, error) { 47 | spec := &peer.ChaincodeInvocationSpec{ 48 | ChaincodeSpec: &peer.ChaincodeSpec{ 49 | ChaincodeId: &peer.ChaincodeID{Name: chaincode}, 50 | Input: &peer.ChaincodeInput{Args: args}, 51 | }, 52 | } 53 | return proto.Marshal(spec) 54 | } 55 | -------------------------------------------------------------------------------- /block/seek.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "github.com/golang/protobuf/proto" 5 | "github.com/hyperledger/fabric-protos-go/orderer" 6 | ) 7 | 8 | // NewSeekSpecified returns orderer.SeekPosition_Specified position 9 | func NewSeekSpecified(number uint64) *orderer.SeekPosition { 10 | return &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: number}}} 11 | } 12 | 13 | func NewSeekInfo(start, stop *orderer.SeekPosition) *orderer.SeekInfo { 14 | return &orderer.SeekInfo{ 15 | Start: start, 16 | Stop: stop, 17 | Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY, 18 | } 19 | } 20 | 21 | func NewMarshalledSeekInfo(start, stop *orderer.SeekPosition) ([]byte, error) { 22 | return proto.Marshal(NewSeekInfo(start, stop)) 23 | } 24 | -------------------------------------------------------------------------------- /block/smartbft/common/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/s7techlab/hlf-sdk-go/block/smartbft/common"; 4 | 5 | package common; 6 | 7 | // Metadata is a common structure to be used to encode block metadata 8 | message BFTMetadata { 9 | bytes value = 1; 10 | repeated BFTMetadataSignature signatures = 2; 11 | } 12 | 13 | message BFTMetadataSignature { 14 | bytes signature_header = 1; // An encoded SignatureHeader 15 | bytes signature = 2; // The signature over the concatenation of the Metadata value bytes, signatureHeader, and block header 16 | uint64 signer_id = 3; 17 | bytes nonce = 4; 18 | } -------------------------------------------------------------------------------- /block/smartbft/configuration.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/s7techlab/hlf-sdk-go/block/smartbft"; 4 | 5 | package smartbft; 6 | 7 | // ConfigMetadata is serialized and set as the value of ConsensusType.Metadata in 8 | // a channel configuration when the ConsensusType.Type is set "smartbft". 9 | message ConfigMetadata { 10 | repeated Consenter consenters = 1; 11 | Options options = 2; 12 | } 13 | 14 | // Consenter represents a consenting node (i.e. replica). 15 | message Consenter { 16 | uint64 consenter_id = 1; 17 | string host = 2; 18 | uint32 port = 3; 19 | string msp_id = 4; 20 | bytes identity = 5; 21 | bytes client_tls_cert = 6; 22 | bytes server_tls_cert = 7; 23 | } 24 | 25 | // Options to be specified for all the smartbft nodes. These can be modified on a 26 | // per-channel basis. 27 | message Options { 28 | reserved "config"; 29 | reserved 1; 30 | 31 | uint64 request_batch_max_count = 2; 32 | uint64 request_batch_max_bytes = 3; 33 | string request_batch_max_interval = 4; 34 | 35 | uint64 incoming_message_buffer_size = 5; 36 | uint64 request_pool_size = 6; 37 | 38 | string request_forward_timeout = 7; 39 | string request_complain_timeout = 8; 40 | string request_auto_remove_timeout = 9; 41 | 42 | string view_change_resend_interval = 10; 43 | string view_change_timeout = 11; 44 | 45 | string leader_heartbeat_timeout = 12; 46 | uint64 leader_heartbeat_count = 13; 47 | 48 | string collect_timeout = 14; 49 | bool sync_on_start = 15; 50 | bool speed_up_view_change = 16; 51 | } -------------------------------------------------------------------------------- /block/transform/action_payload.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/golang/protobuf/proto" 8 | 9 | hlfproto "github.com/s7techlab/hlf-sdk-go/block" 10 | ) 11 | 12 | type ( 13 | ActionPayloadTransformer interface { 14 | Transform(*hlfproto.TransactionAction) error 15 | } 16 | ActionPayloadMatch func(string) bool 17 | ActionPayloadMutate func(*hlfproto.TransactionAction) error 18 | 19 | ActionPayload struct { 20 | match ActionPayloadMatch 21 | mutators []ActionPayloadMutate 22 | } 23 | ) 24 | 25 | func NewActionPayload(match ActionPayloadMatch, mutators ...ActionPayloadMutate) *ActionPayload { 26 | return &ActionPayload{ 27 | match: match, 28 | mutators: mutators, 29 | } 30 | } 31 | 32 | func (action *ActionPayload) Transform(txAction *hlfproto.TransactionAction) error { 33 | args := txAction.ChaincodeSpec().GetInput().GetArgs() 34 | if len(args) == 0 { 35 | return nil 36 | } 37 | 38 | // args[0] save name method 39 | if action.match(string(args[0])) { 40 | for _, mutate := range action.mutators { 41 | if err := mutate(txAction); err != nil { 42 | return fmt.Errorf(`Action payload mutate: %w`, err) 43 | } 44 | } 45 | } 46 | return nil 47 | } 48 | 49 | func ActionPayloadMatchFunc(str string) ActionPayloadMatch { 50 | return func(methodName string) bool { 51 | return methodName == str 52 | } 53 | } 54 | 55 | func ActionPayloadMutateProto(target proto.Message) ActionPayloadMutate { 56 | return func(txAction *hlfproto.TransactionAction) error { 57 | responsePayload := txAction.Response().GetPayload() 58 | 59 | if len(responsePayload) == 0 { 60 | return nil 61 | } 62 | 63 | if string(responsePayload)[:1] == "{" { 64 | return nil 65 | } 66 | 67 | payloadJSON, err := Proto2JSON(responsePayload, target) 68 | if err != nil { 69 | log.Printf("%s", err) 70 | } 71 | 72 | txAction.Payload.Action.ProposalResponsePayload.Extension.Response.Payload = ReplaceBytesU0000ToNullBytes(payloadJSON) 73 | return nil 74 | } 75 | } 76 | 77 | func ActionPayloadProto(methodName string, txAction proto.Message) *ActionPayload { 78 | return NewActionPayload( 79 | ActionPayloadMatchFunc(methodName), 80 | ActionPayloadMutateProto(txAction), 81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /block/transform/args.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/golang/protobuf/proto" 7 | ) 8 | 9 | type ( 10 | InputArgsTransformer interface { 11 | Transform([][]byte) error 12 | } 13 | InputArgsMatch func([][]byte) bool 14 | InputArgsMutate func([][]byte) error 15 | 16 | InputArgs struct { 17 | match InputArgsMatch 18 | mutate InputArgsMutate 19 | } 20 | ) 21 | 22 | func NewInputArgs(match InputArgsMatch, mutate InputArgsMutate) *InputArgs { 23 | return &InputArgs{ 24 | match: match, 25 | mutate: mutate, 26 | } 27 | } 28 | 29 | func (tr *InputArgs) Transform(args [][]byte) error { 30 | if tr.match(args) { 31 | return tr.mutate(args) 32 | } 33 | return nil 34 | } 35 | 36 | func InputArgsProto(fn string, target proto.Message) *InputArgs { 37 | return NewInputArgs( 38 | InputArgsMatchFunc(fn), 39 | InputArgsMutateProto(target), 40 | ) 41 | } 42 | 43 | func InputArgsMatchFunc(fn string) InputArgsMatch { 44 | return InputArgsMatchString(0, fn) // fn is on pos=0 45 | } 46 | 47 | func InputArgsMatchString(pos int, str string) InputArgsMatch { 48 | return func(args [][]byte) bool { 49 | if len(args) > pos && string(args[pos]) == str { 50 | return true 51 | } 52 | return false 53 | } 54 | } 55 | 56 | func InputArgsMutateProtoAtPos(target proto.Message, pos int) InputArgsMutate { 57 | return func(args [][]byte) error { 58 | if len(args) < pos+1 || len(args[pos]) == 0 { 59 | return nil 60 | } 61 | arg, err := Proto2JSON(args[pos], target) 62 | if err != nil { 63 | return fmt.Errorf(`args mutator pos=%d: %w`, pos, err) 64 | } 65 | 66 | args[pos] = arg 67 | return nil 68 | } 69 | } 70 | 71 | func InputArgsMutateProto(target proto.Message) InputArgsMutate { 72 | return InputArgsMutateProtoAtPos(target, 1) // args[0] - func name, args[1] - proto by default 73 | } 74 | -------------------------------------------------------------------------------- /block/transform/event.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/golang/protobuf/proto" 7 | "github.com/hyperledger/fabric-protos-go/peer" 8 | ) 9 | 10 | type ( 11 | EventTransformer interface { 12 | Transform(*peer.ChaincodeEvent) error 13 | } 14 | EventMatch func(string) bool 15 | EventMutate func(*peer.ChaincodeEvent) error 16 | 17 | Event struct { 18 | match EventMatch 19 | mutate EventMutate 20 | } 21 | ) 22 | 23 | func NewEvent(match EventMatch, mutate EventMutate) *Event { 24 | return &Event{ 25 | match: match, 26 | mutate: mutate, 27 | } 28 | } 29 | 30 | func (e *Event) Transform(event *peer.ChaincodeEvent) error { 31 | if e.match(event.EventName) { 32 | return e.mutate(event) 33 | } 34 | return nil 35 | } 36 | 37 | func EventProto(eventName string, target proto.Message) *Event { 38 | return NewEvent( 39 | EventMatchFunc(eventName), 40 | EventMutateProto(target), 41 | ) 42 | } 43 | 44 | func EventMatchFunc(str string) EventMatch { 45 | return func(eventName string) bool { 46 | return eventName == str 47 | } 48 | } 49 | 50 | func EventMutateProto(target proto.Message) EventMutate { 51 | return func(event *peer.ChaincodeEvent) error { 52 | payloadJSON, err := Proto2JSON(event.Payload, target) 53 | if err != nil { 54 | return fmt.Errorf(`event payload mutator: %w`, err) 55 | } 56 | 57 | event.Payload = payloadJSON 58 | return nil 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /block/transform/map_prefix.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | func MappingPrefixes(mapping map[string]string) []string { 4 | prefixes := make([]string, 0) 5 | for prefix := range mapping { 6 | prefixes = append(prefixes, prefix) 7 | } 8 | 9 | return prefixes 10 | } 11 | -------------------------------------------------------------------------------- /block/transform/proto.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/golang/protobuf/jsonpb" 8 | "github.com/golang/protobuf/proto" 9 | ) 10 | 11 | var jsonpbMarshaler = &jsonpb.Marshaler{EmitDefaults: true} 12 | 13 | func Proto2JSON(serialized []byte, target proto.Message) ([]byte, error) { 14 | m := proto.Clone(target) 15 | 16 | if err := proto.Unmarshal(serialized, m); err != nil { 17 | return nil, fmt.Errorf(`proto unmarshal to=%s: %w`, reflect.TypeOf(target), err) 18 | } 19 | 20 | s, err := jsonpbMarshaler.MarshalToString(m) 21 | if err != nil { 22 | return nil, fmt.Errorf(`json pb marshal: %w`, err) 23 | } 24 | 25 | return []byte(s), nil 26 | } 27 | -------------------------------------------------------------------------------- /block/transform/replace_bytes.go: -------------------------------------------------------------------------------- 1 | package transform 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | ) 7 | 8 | const ( 9 | nullByte = "\x00" 10 | alternativeNullByte = "\\u0000" 11 | keySeparator = `_` 12 | ) 13 | 14 | var ( 15 | byteNullByte = []byte(nullByte) 16 | byteAlternativeNullByte = []byte(`\\u0000`) 17 | ) 18 | 19 | func ReplaceBytesU0000ToNullBytes(str []byte) []byte { 20 | if str == nil { 21 | return nil 22 | } 23 | 24 | return bytes.ReplaceAll(str, byteAlternativeNullByte, byteNullByte) 25 | } 26 | 27 | func ReplaceStringSeparatorToNullBytes(str string) string { 28 | if len(str) == 0 { 29 | return "" 30 | } 31 | return strings.ReplaceAll(str, keySeparator, nullByte) 32 | } 33 | 34 | func ReplaceStringNullBytesToSeparator(str string) string { 35 | if len(str) == 0 { 36 | return "" 37 | } 38 | return strings.ReplaceAll(str, nullByte, keySeparator) 39 | } 40 | 41 | func RemoveStringNullBytes(str string) string { 42 | if len(str) == 0 { 43 | return "" 44 | } 45 | str = strings.ReplaceAll(str, nullByte, ``) 46 | return strings.ReplaceAll(str, alternativeNullByte, ``) 47 | } 48 | 49 | func RemoveBytesNullBytes(str []byte) []byte { 50 | if str == nil { 51 | return nil 52 | } 53 | str = bytes.ReplaceAll(str, byteNullByte, []byte{}) 54 | return bytes.ReplaceAll(str, byteAlternativeNullByte, []byte{}) 55 | } 56 | -------------------------------------------------------------------------------- /block/transformer.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | // Transformer transforms parsed observer data. For example decrypt, or transformer protobuf state to json 4 | type Transformer interface { 5 | Transform(*Block) (*Block, error) 6 | } 7 | -------------------------------------------------------------------------------- /block/tx.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hyperledger/fabric-protos-go/common" 7 | "github.com/hyperledger/fabric-protos-go/peer" 8 | "github.com/hyperledger/fabric/protoutil" 9 | ) 10 | 11 | func (x *Transaction) Events() []*peer.ChaincodeEvent { 12 | var events []*peer.ChaincodeEvent 13 | for _, a := range x.Actions { 14 | event := a.GetPayload().GetAction().GetProposalResponsePayload().GetExtension().GetEvents() 15 | if event != nil { 16 | events = append(events, event) 17 | } 18 | } 19 | return events 20 | } 21 | 22 | func ParseEndorserTransaction(payload *common.Payload) (*Transaction, error) { 23 | var actions []*TransactionAction 24 | tx, err := protoutil.UnmarshalTransaction(payload.Data) 25 | if err != nil { 26 | return nil, fmt.Errorf("unmarshal transaction from payload data: %w", err) 27 | } 28 | 29 | actions, err = ParseTxActions(tx.Actions) 30 | if err != nil { 31 | return nil, fmt.Errorf("parse transaction actions: %w", err) 32 | } 33 | 34 | return &Transaction{ 35 | Actions: actions, 36 | }, nil 37 | } 38 | -------------------------------------------------------------------------------- /block/txflags/validation_flags.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package txflags 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-protos-go/peer" 11 | ) 12 | 13 | // ValidationFlags is array of transaction validation codes. It is used when committer validates block. 14 | type ValidationFlags []uint8 15 | 16 | // New create new object-array of validation codes with target size. 17 | // Default values: TxValidationCode_NOT_VALIDATED 18 | func New(size int) ValidationFlags { 19 | return newWithValues(size, peer.TxValidationCode_NOT_VALIDATED) 20 | } 21 | 22 | // NewWithValues creates new object-array of validation codes with target size 23 | // and the supplied value 24 | func NewWithValues(size int, value peer.TxValidationCode) ValidationFlags { 25 | return newWithValues(size, value) 26 | } 27 | 28 | func newWithValues(size int, value peer.TxValidationCode) ValidationFlags { 29 | inst := make(ValidationFlags, size) 30 | for i := range inst { 31 | inst[i] = uint8(value) 32 | } 33 | 34 | return inst 35 | } 36 | 37 | // SetFlag assigns validation code to specified transaction 38 | func (obj ValidationFlags) SetFlag(txIndex int, flag peer.TxValidationCode) { 39 | obj[txIndex] = uint8(flag) 40 | } 41 | 42 | // Flag returns validation code at specified transaction 43 | func (obj ValidationFlags) Flag(txIndex int) peer.TxValidationCode { 44 | return peer.TxValidationCode(obj[txIndex]) 45 | } 46 | 47 | // IsValid checks if specified transaction is valid 48 | func (obj ValidationFlags) IsValid(txIndex int) bool { 49 | return obj.IsSetTo(txIndex, peer.TxValidationCode_VALID) 50 | } 51 | 52 | // IsInvalid checks if specified transaction is invalid 53 | func (obj ValidationFlags) IsInvalid(txIndex int) bool { 54 | return !obj.IsValid(txIndex) 55 | } 56 | 57 | // IsSetTo returns true if the specified transaction equals flag; false otherwise. 58 | func (obj ValidationFlags) IsSetTo(txIndex int, flag peer.TxValidationCode) bool { 59 | return obj.Flag(txIndex) == flag 60 | } 61 | -------------------------------------------------------------------------------- /block/txflags/validation_flags_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright IBM Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package txflags 8 | 9 | import ( 10 | "testing" 11 | 12 | "github.com/hyperledger/fabric-protos-go/peer" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | func TestTransactionValidationFlags(t *testing.T) { 17 | txFlags := NewWithValues(10, peer.TxValidationCode_VALID) 18 | require.Equal(t, 10, len(txFlags)) 19 | 20 | txFlags.SetFlag(0, peer.TxValidationCode_VALID) 21 | require.Equal(t, peer.TxValidationCode_VALID, txFlags.Flag(0)) 22 | require.Equal(t, true, txFlags.IsValid(0)) 23 | 24 | txFlags.SetFlag(1, peer.TxValidationCode_MVCC_READ_CONFLICT) 25 | require.Equal(t, true, txFlags.IsInvalid(1)) 26 | } 27 | -------------------------------------------------------------------------------- /buf.gen.go.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | 3 | plugins: 4 | 5 | - name: go 6 | path: .generators/bin/protoc-gen-go 7 | out: . 8 | opt: 9 | - plugins=grpc 10 | - paths=source_relative 11 | 12 | - name: go-validate 13 | path: .generators/bin/protoc-gen-validate 14 | out: . 15 | opt: 16 | - paths=source_relative 17 | - lang=go 18 | -------------------------------------------------------------------------------- /buf.gen.svc.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | 3 | plugins: 4 | 5 | - name: go 6 | path: .generators/bin/protoc-gen-go 7 | out: . 8 | opt: 9 | - plugins=grpc 10 | - paths=source_relative 11 | 12 | - name: go-validate 13 | path: .generators/bin/protoc-gen-validate 14 | out: . 15 | opt: 16 | - paths=source_relative 17 | - lang=go 18 | 19 | - name: swagger 20 | path: .generators/bin/protoc-gen-swagger 21 | out: . 22 | opt: 23 | - logtostderr=true 24 | 25 | - name: grpc-gateway 26 | path: .generators/bin/protoc-gen-grpc-gateway 27 | out: . 28 | opt: 29 | - logtostderr=true 30 | - paths=source_relative 31 | -------------------------------------------------------------------------------- /buf.work.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | directories: 3 | - block 4 | - service 5 | - third_party 6 | -------------------------------------------------------------------------------- /client/ca/client.go: -------------------------------------------------------------------------------- 1 | package ca 2 | 3 | import ( 4 | "context" 5 | "crypto/x509" 6 | "crypto/x509/pkix" 7 | ) 8 | 9 | type Client interface { 10 | // CAInfo Getting information about CA 11 | CAInfo(ctx context.Context) (*ResponseCAInfo, error) 12 | 13 | Register(ctx context.Context, req RegistrationRequest) (string, error) 14 | Enroll(ctx context.Context, name, secret string, req *x509.CertificateRequest, opts ...EnrollOpt) ( 15 | *x509.Certificate, interface{}, error) 16 | Revoke(ctx context.Context, req RevocationRequest) (*pkix.CertificateList, error) 17 | 18 | IdentityList(ctx context.Context) ([]Identity, error) 19 | IdentityGet(ctx context.Context, enrollId string) (*Identity, error) 20 | 21 | CertificateList(ctx context.Context, opts ...CertificateListOpt) ([]*x509.Certificate, error) 22 | 23 | // AffiliationList lists all affiliations and identities of identity affiliation 24 | AffiliationList(ctx context.Context, rootAffiliation ...string) ([]Identity, []Affiliation, error) 25 | AffiliationCreate(ctx context.Context, name string, opts ...AffiliationOpt) error 26 | AffiliationDelete(ctx context.Context, name string, opts ...AffiliationOpt) ([]Identity, []Affiliation, error) 27 | } 28 | -------------------------------------------------------------------------------- /client/ca/entity.go: -------------------------------------------------------------------------------- 1 | package ca 2 | 3 | type ( 4 | Identity struct { 5 | Id string `json:"id"` 6 | Type string `json:"type"` 7 | MaxEnrollments int `json:"max_enrollments"` 8 | Name string `json:"name"` 9 | Attrs []IdentityAttribute `json:"attrs"` 10 | } 11 | 12 | IdentityAttribute struct { 13 | Name string `json:"name"` 14 | Value string `json:"value"` 15 | ECert bool `json:"ecert"` 16 | } 17 | 18 | RevokedCert struct { 19 | Serial string 20 | AKI string 21 | } 22 | 23 | Affiliation struct { 24 | Name string `json:"name"` 25 | Affiliations []Affiliation `json:"affiliations,omitempty"` 26 | Identities []Identity `json:"identities,omitempty"` 27 | } 28 | ) 29 | -------------------------------------------------------------------------------- /client/ca/errors.go: -------------------------------------------------------------------------------- 1 | package ca 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type ResponseError struct { 9 | Errors []ResponseMessage 10 | Messages []ResponseMessage 11 | } 12 | 13 | func (err ResponseError) Error() string { 14 | return fmt.Sprintf("CA response error messages: %s", err.joinErrors()) 15 | } 16 | 17 | func (err ResponseError) joinErrors() string { 18 | mes := make([]string, len(err.Errors)) 19 | for i, m := range err.Errors { 20 | mes[i] = m.Message 21 | } 22 | 23 | return strings.Join(mes, `,`) 24 | } 25 | -------------------------------------------------------------------------------- /client/ca/http/certificate.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "crypto/x509" 6 | "encoding/pem" 7 | "fmt" 8 | "net/http" 9 | "net/url" 10 | 11 | "github.com/pkg/errors" 12 | 13 | "github.com/s7techlab/hlf-sdk-go/client/ca" 14 | ) 15 | 16 | const endpointCertificateList = "%s/api/v1/certificates%s" 17 | 18 | func (c *Client) CertificateList(ctx context.Context, opts ...ca.CertificateListOpt) ([]*x509.Certificate, error) { 19 | var ( 20 | reqUrl string 21 | err error 22 | ) 23 | 24 | u := url.Values{} 25 | for _, opt := range opts { 26 | if err = opt(&u); err != nil { 27 | return nil, errors.Wrap(err, `failed to apply opt`) 28 | } 29 | } 30 | 31 | if v := u.Encode(); v == `` { 32 | reqUrl = fmt.Sprintf(endpointCertificateList, c.config.Host, ``) 33 | } else { 34 | reqUrl = fmt.Sprintf(endpointCertificateList, c.config.Host, `?`+v) 35 | } 36 | 37 | req, err := http.NewRequest(http.MethodGet, reqUrl, nil) 38 | if err != nil { 39 | return nil, errors.Wrap(err, `failed to create request`) 40 | } 41 | 42 | if err = c.setAuthToken(req, nil); err != nil { 43 | return nil, errors.Wrap(err, `failed to set authorization token`) 44 | } 45 | 46 | req = req.WithContext(ctx) 47 | 48 | resp, err := c.client.Do(req) 49 | if err != nil { 50 | return nil, errors.Wrap(err, `failed to process request`) 51 | } 52 | 53 | var certResponse ca.ResponseCertificateList 54 | 55 | if err = c.processResponse(resp, &certResponse, http.StatusOK); err != nil { 56 | return nil, err 57 | } 58 | 59 | certs := make([]*x509.Certificate, len(certResponse.Certs)) 60 | for i, v := range certResponse.Certs { 61 | b, _ := pem.Decode([]byte(v.PEM)) 62 | if b == nil { 63 | return nil, errors.Errorf("failed to parse PEM block: %s", v) 64 | } 65 | if cert, err := x509.ParseCertificate(b.Bytes); err != nil { 66 | return nil, errors.Wrap(err, `failed to parse certificate`) 67 | } else { 68 | certs[i] = cert 69 | } 70 | } 71 | 72 | return certs, nil 73 | } 74 | -------------------------------------------------------------------------------- /client/ca/http/identity.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/pkg/errors" 9 | 10 | "github.com/s7techlab/hlf-sdk-go/client/ca" 11 | ) 12 | 13 | const ( 14 | endpointIdentityList = "%s/api/v1/identities" 15 | endpointIdentityGet = "%s/api/v1/identities/%s" 16 | ) 17 | 18 | func (c *Client) IdentityList(ctx context.Context) ([]ca.Identity, error) { 19 | req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(endpointIdentityList, c.config.Host), nil) 20 | if err != nil { 21 | return nil, errors.Wrap(err, `failed to create request`) 22 | } 23 | 24 | req = req.WithContext(ctx) 25 | 26 | if err = c.setAuthToken(req, nil); err != nil { 27 | return nil, errors.Wrap(err, `failed to set auth token`) 28 | } 29 | 30 | resp, err := c.client.Do(req) 31 | if err != nil { 32 | return nil, errors.Wrap(err, `failed to process request`) 33 | } 34 | 35 | var identityListResp ca.ResponseIdentityList 36 | 37 | if err = c.processResponse(resp, &identityListResp, http.StatusOK); err != nil { 38 | return nil, err 39 | } 40 | 41 | return identityListResp.Identities, nil 42 | } 43 | 44 | func (c *Client) IdentityGet(ctx context.Context, enrollId string) (*ca.Identity, error) { 45 | req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(endpointIdentityGet, c.config.Host, enrollId), nil) 46 | 47 | if err != nil { 48 | return nil, errors.Wrap(err, `failed to create request`) 49 | } 50 | 51 | req = req.WithContext(ctx) 52 | 53 | if err = c.setAuthToken(req, nil); err != nil { 54 | return nil, errors.Wrap(err, `failed to set auth token`) 55 | } 56 | 57 | resp, err := c.client.Do(req) 58 | if err != nil { 59 | return nil, errors.Wrap(err, `failed to process request`) 60 | } 61 | 62 | var identity ca.Identity 63 | 64 | if err = c.processResponse(resp, &identity, http.StatusOK); err != nil { 65 | return nil, err 66 | } 67 | 68 | return &identity, nil 69 | } 70 | -------------------------------------------------------------------------------- /client/ca/http/info.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/pkg/errors" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/client/ca" 10 | ) 11 | 12 | func (c *Client) CAInfo(ctx context.Context) (*ca.ResponseCAInfo, error) { 13 | req, err := http.NewRequest(http.MethodGet, c.config.Host+`/api/v1/cainfo`, nil) 14 | if err != nil { 15 | return nil, errors.Wrap(err, `failed to create http request`) 16 | } 17 | 18 | resp, err := c.client.Do(req.WithContext(ctx)) 19 | if err != nil { 20 | return nil, errors.Wrap(err, `failed to process http request`) 21 | } 22 | 23 | var caInfoResp ca.ResponseCAInfo 24 | 25 | if err = c.processResponse(resp, &caInfoResp, http.StatusOK); err != nil { 26 | return nil, err 27 | } 28 | 29 | return &caInfoResp, nil 30 | } 31 | -------------------------------------------------------------------------------- /client/ca/http/opts.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | 8 | "gopkg.in/yaml.v2" 9 | 10 | "github.com/s7techlab/hlf-sdk-go/api/config" 11 | ) 12 | 13 | type Opt func(c *Client) error 14 | 15 | // WithYamlConfig allows using YAML config from file 16 | func WithYamlConfig(configPath string) Opt { 17 | return func(c *Client) error { 18 | if configBytes, err := os.ReadFile(configPath); err != nil { 19 | return fmt.Errorf(`read file=%s: %w`, configPath, err) 20 | } else { 21 | c.config = new(config.CAConfig) 22 | if err = yaml.Unmarshal(configBytes, c.config); err != nil { 23 | return fmt.Errorf(`unmarshal YAML config: %w`, err) 24 | } 25 | } 26 | return nil 27 | } 28 | } 29 | 30 | func WithBytesConfig(configBytes []byte) Opt { 31 | return func(c *Client) error { 32 | if err := yaml.Unmarshal(configBytes, c.config); err != nil { 33 | return fmt.Errorf(`unmarshal YAML config: %w`, err) 34 | } 35 | return nil 36 | } 37 | } 38 | 39 | func WithRawConfig(conf *config.CAConfig) Opt { 40 | return func(c *Client) error { 41 | c.config = conf 42 | return nil 43 | } 44 | } 45 | 46 | func WithHTTPClient(client *http.Client) Opt { 47 | return func(c *Client) error { 48 | c.client = client 49 | return nil 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /client/ca/http/register.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "net/http" 8 | 9 | "github.com/pkg/errors" 10 | 11 | "github.com/s7techlab/hlf-sdk-go/client/ca" 12 | ) 13 | 14 | const regEndpoint = `/api/v1/register` 15 | 16 | func (c *Client) Register(ctx context.Context, req ca.RegistrationRequest) (string, error) { 17 | reqBytes, err := json.Marshal(req) 18 | if err != nil { 19 | return ``, errors.Wrap(err, `failed to marshal request to JSON`) 20 | } 21 | 22 | authToken, err := c.createAuthToken(reqBytes) 23 | if err != nil { 24 | return ``, errors.Wrap(err, `failed to get auth token`) 25 | } 26 | 27 | httpReq, err := http.NewRequest(http.MethodPost, c.config.Host+regEndpoint, bytes.NewBuffer(reqBytes)) 28 | if err != nil { 29 | return ``, errors.Wrap(err, `failed to create http request`) 30 | } 31 | 32 | httpReq.Header.Set(`Content-Type`, `application/json`) 33 | httpReq.Header.Set(`authorization`, authToken) 34 | 35 | resp, err := c.client.Do(httpReq.WithContext(ctx)) 36 | if err != nil { 37 | return ``, errors.Wrap(err, `failed to get response`) 38 | } 39 | 40 | var regResp ca.ResponseRegistration 41 | 42 | if err = c.processResponse(resp, ®Resp, http.StatusCreated); err != nil { 43 | return ``, err 44 | } 45 | 46 | return regResp.Secret, nil 47 | } 48 | -------------------------------------------------------------------------------- /client/ca/http/revoke.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/x509" 7 | "crypto/x509/pkix" 8 | "encoding/json" 9 | "fmt" 10 | "net/http" 11 | 12 | "github.com/pkg/errors" 13 | 14 | "github.com/s7techlab/hlf-sdk-go/client/ca" 15 | ) 16 | 17 | const ( 18 | endpointRevoke = "%s/api/v1/revoke" 19 | ) 20 | 21 | func (c *Client) Revoke(ctx context.Context, req ca.RevocationRequest) (*pkix.CertificateList, error) { 22 | reqBytes, err := json.Marshal(req) 23 | if err != nil { 24 | return nil, errors.Wrap(err, `failed to marshal JSON request`) 25 | } 26 | 27 | httpReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf(endpointRevoke, c.config.Host), bytes.NewBuffer(reqBytes)) 28 | if err != nil { 29 | return nil, errors.Wrap(err, `failed to create request`) 30 | } 31 | 32 | if err = c.setAuthToken(httpReq, reqBytes); err != nil { 33 | return nil, errors.Wrap(err, `failed to set auth token`) 34 | } 35 | 36 | resp, err := c.client.Do(httpReq.WithContext(ctx)) 37 | if err != nil { 38 | return nil, errors.Wrap(err, `failed to process request`) 39 | } 40 | 41 | var revokeResponse ca.ResponseRevoke 42 | 43 | if err = c.processResponse(resp, &revokeResponse, http.StatusOK); err != nil { 44 | return nil, err 45 | } 46 | 47 | if crl, err := x509.ParseCRL(revokeResponse.CRL); err != nil { 48 | return nil, errors.Wrap(err, `failed to parse CRL`) 49 | } else { 50 | return crl, nil 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /client/ca/mock/ca_test.go: -------------------------------------------------------------------------------- 1 | package mock_test 2 | 3 | import ( 4 | "context" 5 | "crypto/x509" 6 | "crypto/x509/pkix" 7 | _ "embed" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | 12 | "github.com/s7techlab/hlf-sdk-go/client/ca" 13 | "github.com/s7techlab/hlf-sdk-go/client/ca/mock" 14 | ) 15 | 16 | var ( 17 | //go:embed testdata/ca.pem 18 | cert []byte 19 | //go:embed testdata/ca-key.pem 20 | pk []byte 21 | 22 | client ca.Client 23 | 24 | ctx = context.Background() 25 | ) 26 | 27 | func TestNewMockCaClientInvalidCert(t *testing.T) { 28 | var err error 29 | client, err = mock.New([]byte(`invalid`), []byte(`invalid_cert`)) 30 | assert.Nil(t, client) 31 | assert.Error(t, err) 32 | } 33 | 34 | func TestNewMockCaClientValid(t *testing.T) { 35 | var err error 36 | client, err = mock.New(pk, cert) 37 | assert.NoError(t, err) 38 | assert.NotNil(t, client) 39 | 40 | } 41 | 42 | func TestCaClient_Enroll(t *testing.T) { 43 | req := &x509.CertificateRequest{Subject: pkix.Name{ 44 | Country: []string{`RU`}, 45 | Organization: []string{`my org`}, 46 | StreetAddress: []string{`my address`}, 47 | CommonName: `org1`, 48 | }} 49 | 50 | certificate, privateKey, err := client.Enroll(ctx, ``, ``, req) 51 | assert.NoError(t, err) 52 | assert.NotNil(t, certificate) 53 | assert.NotNil(t, privateKey) 54 | 55 | assert.Equal(t, certificate.Subject.CommonName, req.Subject.CommonName) 56 | } 57 | -------------------------------------------------------------------------------- /client/ca/mock/testdata/README.md: -------------------------------------------------------------------------------- 1 | # Generate test CA keypair 2 | 3 | cfssl genkey -initca csr.json | cfssljson -bare ca 4 | -------------------------------------------------------------------------------- /client/ca/mock/testdata/ca-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIGkAgEBBDCcZa88Grdt/9/lm48PJIJ0v5U39seRpZKsHh0imLEXTYJAgQ3WUgUE 3 | AHu3PQMmKYKgBwYFK4EEACKhZANiAAQp04NuaWKg058oPqMYLSH/UJPUKph9HfOG 4 | BPOKfFRDMVd55bMD0xCZo4X4D15oYiMZMKm3IuK6lQ8SBClCsN2tasDdIUlMd4RA 5 | J71cuom8EWfVk8XiFSXQ+Lw0G8CvQ4o= 6 | -----END EC PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /client/ca/mock/testdata/ca.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIBXzCB5QIBADBEMQowCAYDVQQGEwFDMQowCAYDVQQHEwFMMRUwEwYDVQQKEwxI 3 | TEYgU2VydmljZXMxEzARBgNVBAMTCkhMRi1TREstR08wdjAQBgcqhkjOPQIBBgUr 4 | gQQAIgNiAAQp04NuaWKg058oPqMYLSH/UJPUKph9HfOGBPOKfFRDMVd55bMD0xCZ 5 | o4X4D15oYiMZMKm3IuK6lQ8SBClCsN2tasDdIUlMd4RAJ71cuom8EWfVk8XiFSXQ 6 | +Lw0G8CvQ4qgIjAgBgkqhkiG9w0BCQ4xEzARMA8GA1UdEwEB/wQFMAMBAf8wCgYI 7 | KoZIzj0EAwMDaQAwZgIxANOSZLlz7g4ObaxZ5YpVrvStuloWWlmbrNTvCB9Mb+1j 8 | j6K+ppDPVtfdabhDxSo2TwIxAJQNn5WE2GjZv4JGsZ8JDRF0rCzUKsDZcd47AUZ0 9 | DK3oHNzNn0pc0E0JXaytZiok9g== 10 | -----END CERTIFICATE REQUEST----- 11 | -------------------------------------------------------------------------------- /client/ca/mock/testdata/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICCjCCAY+gAwIBAgIUeqQydpuOH1Xc+fTV0VjjUOWFyIIwCgYIKoZIzj0EAwMw 3 | RDEKMAgGA1UEBhMBQzEKMAgGA1UEBxMBTDEVMBMGA1UEChMMSExGIFNlcnZpY2Vz 4 | MRMwEQYDVQQDEwpITEYtU0RLLUdPMB4XDTIzMDUyOTA2NDYwMFoXDTI4MDQxMjA2 5 | NDYwMFowRDEKMAgGA1UEBhMBQzEKMAgGA1UEBxMBTDEVMBMGA1UEChMMSExGIFNl 6 | cnZpY2VzMRMwEQYDVQQDEwpITEYtU0RLLUdPMHYwEAYHKoZIzj0CAQYFK4EEACID 7 | YgAEKdODbmlioNOfKD6jGC0h/1CT1CqYfR3zhgTzinxUQzFXeeWzA9MQmaOF+A9e 8 | aGIjGTCptyLiupUPEgQpQrDdrWrA3SFJTHeEQCe9XLqJvBFn1ZPF4hUl0Pi8NBvA 9 | r0OKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E 10 | FgQUWj36mvlNlHamSY9UZNCYd/3CwuswCgYIKoZIzj0EAwMDaQAwZgIxAMl1B8M4 11 | ypd/PffZyC+6TRYqVWq68yNBLM0GAu/uNm8ITvzZKxBmZ92hiU8sNbfo8QIxAMS9 12 | z+6VcEVBIca+ZCyiMDlh4tsO/8+DlWReUXUDjrj2W4n9sQ2R6s6wiAqzXxt92g== 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /client/ca/mock/testdata/csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "CN": "HLF-SDK-GO", 3 | "key": { 4 | "algo": "ecdsa", 5 | "size": 384 6 | }, 7 | "names": [ 8 | { 9 | "C": "C", 10 | "L": "L", 11 | "O": "HLF Services", 12 | "OU": "", 13 | "ST": "" 14 | } 15 | ], 16 | "ca": { 17 | "expiry": "42720h" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/ca/opts.go: -------------------------------------------------------------------------------- 1 | package ca 2 | 3 | import ( 4 | "net/url" 5 | ) 6 | 7 | type EnrollProfile string 8 | 9 | const ( 10 | // EnrollProfileDefault asks Fabric CA for certificate used for signing 11 | EnrollProfileDefault EnrollProfile = "" 12 | // EnrollProfileTls asks Fabric CA for certificate used for TLS communication 13 | EnrollProfileTls EnrollProfile = "tls" 14 | ) 15 | 16 | type EnrollOpts struct { 17 | PrivateKey interface{} 18 | Profile EnrollProfile 19 | } 20 | 21 | type EnrollOpt func(opts *EnrollOpts) error 22 | 23 | // WithEnrollPrivateKey allows to use previously created private key 24 | func WithEnrollPrivateKey(privateKey interface{}) EnrollOpt { 25 | return func(opts *EnrollOpts) error { 26 | opts.PrivateKey = privateKey 27 | return nil 28 | } 29 | } 30 | 31 | // WithEnrollProfile allows to require profile of enrolled certificate 32 | func WithEnrollProfile(profile EnrollProfile) EnrollOpt { 33 | return func(opts *EnrollOpts) error { 34 | opts.Profile = profile 35 | return nil 36 | } 37 | } 38 | 39 | type CertificateListOpt func(values *url.Values) error 40 | 41 | func WithEnrollId(enrollId string) CertificateListOpt { 42 | return func(values *url.Values) error { 43 | values.Add(`id`, enrollId) 44 | return nil 45 | } 46 | } 47 | 48 | type AffiliationOpt func(values *url.Values) error 49 | 50 | func WithForce() AffiliationOpt { 51 | return func(values *url.Values) error { 52 | values.Set(`force`, `true`) 53 | return nil 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /client/ca/response.go: -------------------------------------------------------------------------------- 1 | package ca 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type ( 8 | Response struct { 9 | Success bool `json:"success"` 10 | Result json.RawMessage `json:"result"` 11 | Errors []ResponseMessage `json:"errors"` 12 | Messages []ResponseMessage `json:"messages"` 13 | } 14 | 15 | ResponseMessage struct { 16 | Code int `json:"code"` 17 | Message string `json:"message"` 18 | } 19 | 20 | ResponseCAInfo struct { 21 | CAName string `json:"CAName"` 22 | CAChain string `json:"CAChain"` 23 | Version string `json:"Version"` 24 | } 25 | 26 | ResponseRegistration struct { 27 | Secret string `json:"secret"` 28 | } 29 | 30 | ResponseEnrollment struct { 31 | Cert string `json:"Cert"` 32 | ServerInfo ResponseCAInfo `json:"ServerInfo"` 33 | } 34 | 35 | ResponseIdentityList struct { 36 | Identities []Identity `json:"identities"` 37 | } 38 | 39 | ResponseCertificateList struct { 40 | CAName string `json:"caname"` 41 | Certs []ResponseCertificateListPEM `json:"certs"` 42 | } 43 | 44 | ResponseCertificateListPEM struct { 45 | PEM string `json:"PEM"` 46 | } 47 | 48 | ResponseRevoke struct { 49 | RevokedCerts []RevokedCert 50 | CRL []byte 51 | } 52 | 53 | ResponseAffiliationList struct { 54 | Name string `json:"name"` 55 | Affiliations []Affiliation `json:"affiliations"` 56 | Identities []Identity `json:"identities"` 57 | CAName string `json:"caname"` 58 | } 59 | 60 | ResponseAffiliationCreate struct { 61 | Name string `json:"name"` 62 | CAName string `json:"caname"` 63 | } 64 | 65 | ResponseAffiliationDelete struct { 66 | ResponseAffiliationList 67 | } 68 | ) 69 | -------------------------------------------------------------------------------- /client/chaincode/core.go: -------------------------------------------------------------------------------- 1 | package chaincode 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hyperledger/fabric/msp" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/api" 10 | ) 11 | 12 | type Core struct { 13 | mspId string 14 | name string 15 | channelName string 16 | endorsingMSPs []string 17 | peerPool api.PeerPool 18 | orderer api.Orderer 19 | 20 | identity msp.SigningIdentity 21 | } 22 | 23 | func NewCore( 24 | mspId, 25 | ccName, 26 | channelName string, 27 | endorsingMSPs []string, 28 | peerPool api.PeerPool, 29 | orderer api.Orderer, 30 | identity msp.SigningIdentity, 31 | ) *Core { 32 | return &Core{ 33 | mspId: mspId, 34 | name: ccName, 35 | channelName: channelName, 36 | endorsingMSPs: endorsingMSPs, 37 | peerPool: peerPool, 38 | orderer: orderer, 39 | identity: identity, 40 | } 41 | } 42 | 43 | func (c *Core) GetPeers() []api.Peer { 44 | peers := make([]api.Peer, 0) 45 | 46 | peersMap := c.peerPool.GetPeers() 47 | for _, endorsingMSP := range c.endorsingMSPs { 48 | if ps, ok := peersMap[endorsingMSP]; ok { 49 | peers = append(peers, ps...) 50 | } 51 | } 52 | 53 | return peers 54 | } 55 | 56 | func (c *Core) Invoke(fn string) api.ChaincodeInvokeBuilder { 57 | return NewInvokeBuilder(c, fn) 58 | } 59 | 60 | func (c *Core) Query(fn string, args ...string) api.ChaincodeQueryBuilder { 61 | return NewQueryBuilder(c, c.identity, fn, args...) 62 | } 63 | 64 | func (c *Core) Subscribe(ctx context.Context) (api.EventCCSubscription, error) { 65 | peerDeliver, err := c.peerPool.DeliverClient(c.mspId, c.identity) 66 | if err != nil { 67 | return nil, fmt.Errorf(`initiate DeliverClient: %w`, err) 68 | } 69 | return peerDeliver.SubscribeCC(ctx, c.channelName, c.name) 70 | } 71 | -------------------------------------------------------------------------------- /client/chaincode/system.go: -------------------------------------------------------------------------------- 1 | package chaincode 2 | 3 | const ( 4 | CSCC = `cscc` 5 | 6 | CSCCJoinChain string = "JoinChain" 7 | CSCCGetConfigBlock string = "GetConfigBlock" 8 | CSCCGetChannels string = "GetChannels" 9 | CSCCGetConfigTree string = `GetConfigTree` // HLF Peer V1.x 10 | CSCCGetChannelConfig string = "GetChannelConfig" // HLF Peer V2 + 11 | 12 | QSCC = `qscc` 13 | LSCC = `lscc` 14 | Lifecycle = `_lifecycle` 15 | ) 16 | -------------------------------------------------------------------------------- /client/chaincode/testdata/config.yaml: -------------------------------------------------------------------------------- 1 | orderer: 2 | host: localhost:7050 3 | useTLS: false 4 | timeout: 5s 5 | 6 | crypto: 7 | type: ecdsa 8 | options: 9 | # Possible curves: P256, P384, P512 10 | curve: P256 11 | # Possible algorithms for signature: SHA256, SHA384, SHA512 12 | signatureAlgorithm: SHA256 13 | # Possible hashing algorithms: SHA2-256, SHA2-384, SHA3-256, SHA3-384 14 | hash: SHA2-256 15 | 16 | discovery: 17 | type: local 18 | options: 19 | channels: 20 | - name: success-network 21 | description: some channel 22 | chaincodes: 23 | - name: my-chaincode 24 | type: golang 25 | version: "0.1" 26 | description: some chaincode 27 | policy: "AND ('org1msp.admin','org2msp.admin','org3msp.admin')" 28 | - name: fail-network 29 | description: some channel 30 | chaincodes: 31 | - name: my-chaincode 32 | type: golang 33 | version: "0.1" 34 | description: some chaincode 35 | policy: "AND ('org1msp.admin','org2msp.admin','org3msp.admin')" 36 | - name: fail-mvcc-network 37 | description: some channel 38 | chaincodes: 39 | - name: my-chaincode 40 | type: golang 41 | version: "0.1" 42 | description: some chaincode 43 | policy: "AND ('org1msp.admin','org2msp.admin','org3msp.admin')" 44 | - name: fail-invalid-org3-network 45 | description: some channel 46 | chaincodes: 47 | - name: my-chaincode 48 | type: golang 49 | version: "0.1" 50 | description: some chaincode 51 | policy: "AND ('org1msp.admin','org2msp.admin','org3msp.admin')" 52 | 53 | msp: 54 | - name: org1msp 55 | endorsers: 56 | - host: 127.0.0.1:7051 57 | - name: org2msp 58 | endorsers: 59 | - host: localhost:7051 60 | - name: org3msp 61 | endorsers: 62 | - host: localhost:7051 -------------------------------------------------------------------------------- /client/chaincode/testdata/msp/admincerts/admincerts.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx 3 | CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g 4 | RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND 5 | T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx 6 | WhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv 7 | cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD 8 | VQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D 9 | AQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf 10 | EkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud 11 | EwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H 12 | ossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz 13 | PzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI 14 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /client/chaincode/testdata/msp/cacerts/cacert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICYjCCAgigAwIBAgIRAL1fEAnz5zp4moJ8MdSb/lYwCgYIKoZIzj0EAwIwgYEx 3 | CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g 4 | RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND 5 | T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx 6 | WhcNMjcxMTEwMTM0MTExWjCBgTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlm 7 | b3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhh 8 | bXBsZS5jb20xDDAKBgNVBAsTA0NPUDEcMBoGA1UEAxMTY2Eub3JnMS5leGFtcGxl 9 | LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGrsQ6oJpk6hDWf63HU3OSNd 10 | bou9KNw/VIee1IngPDI4YJU7O+Xa/XLJuwnFv7BpR8Ytl3f+njC8i/RZP2/svO+j 11 | XzBdMA4GA1UdDwEB/wQEAwIBpjAPBgNVHSUECDAGBgRVHSUAMA8GA1UdEwEB/wQF 12 | MAMBAf8wKQYDVR0OBCIEIIpzkSIZzxBWVIV5unlgZJuyu2XPEeP8+y1uB6LLA5Qr 13 | MAoGCCqGSM49BAMCA0gAMEUCIQDUh/+CC2dAICnYtACXspwUaaEbiyZxYIx+XDvW 14 | o8VVcgIgGz5S4iC5+xkxgeaISPfxKTTVy6yzTdYGzCw1vPppjzo= 15 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /client/chaincode/testdata/msp/keystore/018f389d200e48536367f05b99122f355ba33572009bd2b8b521cdbbb717a5b5_sk: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgXa3mln4anewXtqrM 3 | hMw6mfZhslkRa/j9P790ToKjlsihRANCAARnxLhXvU4EmnIwhVl3Bh0VcByQi2um 4 | 9KsJ/QdCDjRZb1dKg447voj5SZ8SSZOUglc/v8DJFFJFTfygjwi+27gz 5 | -----END PRIVATE KEY----- -------------------------------------------------------------------------------- /client/chaincode/testdata/msp/signcerts/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx 3 | CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g 4 | RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND 5 | T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx 6 | WhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv 7 | cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD 8 | VQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D 9 | AQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf 10 | EkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud 11 | EwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H 12 | ossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz 13 | PzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI 14 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /client/chaincode/tw_waiter.go: -------------------------------------------------------------------------------- 1 | package chaincode 2 | 3 | import ( 4 | "github.com/s7techlab/hlf-sdk-go/api" 5 | ) 6 | 7 | // TxWaitBuilder function signature for pluggable setter on Do options 8 | type TxWaitBuilder func(cfg *api.DoOptions) (api.TxWaiter, error) 9 | 10 | // WithTxWaiter - add option for set custom tx waiter 11 | func WithTxWaiter(builder TxWaitBuilder) api.DoOption { 12 | return func(cfg *api.DoOptions) (err error) { 13 | cfg.TxWaiter, err = builder(cfg) 14 | return 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/chaincode/txwaiter/all.go: -------------------------------------------------------------------------------- 1 | package txwaiter 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | 7 | "github.com/pkg/errors" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/api" 10 | clienterr "github.com/s7techlab/hlf-sdk-go/client/errors" 11 | ) 12 | 13 | // All - need use on invoke flow for check transaction codes for each organization from endorsement policy 14 | // txwaiter.All will be made to subscribe tx for each of the peer organizations from the endorsement policy 15 | func All(cfg *api.DoOptions) (api.TxWaiter, error) { 16 | waiter := &allMspWaiter{ 17 | onceSet: new(sync.Once), 18 | } 19 | 20 | // make delivers for each mspID 21 | errD := new(clienterr.MultiError) 22 | for i := range cfg.EndorsingMspIDs { 23 | peerDeliver, err := cfg.Pool.DeliverClient(cfg.EndorsingMspIDs[i], cfg.Identity) 24 | if err != nil { 25 | errD.Add(errors.Wrapf(err, "%s: failed to get delivery client", cfg.EndorsingMspIDs[i])) 26 | continue 27 | } 28 | 29 | waiter.delivers = append(waiter.delivers, peerDeliver) 30 | } 31 | if len(errD.Errors) != 0 { 32 | return nil, errD 33 | } 34 | 35 | return waiter, nil 36 | } 37 | 38 | type allMspWaiter struct { 39 | delivers []api.DeliverClient 40 | onceSet *sync.Once 41 | hasErr bool 42 | } 43 | 44 | func (w *allMspWaiter) setErr() { 45 | w.onceSet.Do(func() { w.hasErr = true }) 46 | } 47 | 48 | // Wait - implementation of api.TxWaiter interface 49 | func (w *allMspWaiter) Wait(ctx context.Context, channel string, txId string) error { 50 | var ( 51 | wg = new(sync.WaitGroup) 52 | errS = make(chan error, len(w.delivers)) 53 | ) 54 | 55 | for i := range w.delivers { 56 | wg.Add(1) 57 | go func(j int) { 58 | err := waitPerOne(ctx, w.delivers[j], channel, txId) 59 | if err != nil { 60 | w.setErr() 61 | errS <- err 62 | } 63 | wg.Done() 64 | }(i) 65 | } 66 | wg.Wait() 67 | close(errS) 68 | 69 | if w.hasErr { 70 | mErr := &clienterr.MultiError{} 71 | for e := range errS { 72 | if e != nil { 73 | mErr.Errors = append(mErr.Errors, e) 74 | } 75 | } 76 | return mErr 77 | } 78 | 79 | return nil 80 | } 81 | 82 | func waitPerOne(ctx context.Context, deliver api.DeliverClient, channelName string, txId string) error { 83 | sub, err := deliver.SubscribeTx(ctx, channelName, txId) 84 | if err != nil { 85 | return errors.Wrap(err, "failed to subscribe on tx event") 86 | } 87 | defer func() { _ = sub.Close() }() 88 | 89 | _, err = sub.Result() 90 | return err 91 | } 92 | -------------------------------------------------------------------------------- /client/chaincode/txwaiter/self.go: -------------------------------------------------------------------------------- 1 | package txwaiter 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hyperledger/fabric/msp" 7 | "github.com/pkg/errors" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/api" 10 | ) 11 | 12 | // Self - default tx waiter and used on invoke flow 13 | // txwaiter.Self make subscribe tx on one peer endorser organization 14 | func Self(cfg *api.DoOptions) (api.TxWaiter, error) { 15 | return &selfPeerWaiter{ 16 | pool: cfg.Pool, 17 | identity: cfg.Identity, 18 | }, nil 19 | } 20 | 21 | type selfPeerWaiter struct { 22 | pool api.PeerPool 23 | identity msp.SigningIdentity 24 | } 25 | 26 | // Wait - implementation of api.TxWaiter interface 27 | func (w *selfPeerWaiter) Wait(ctx context.Context, channel string, txID string) error { 28 | mspID := w.identity.GetMSPIdentifier() 29 | deliver, err := w.pool.DeliverClient(mspID, w.identity) 30 | if err != nil { 31 | return errors.Wrapf(err, "%s: failed to get delivery client", mspID) 32 | } 33 | 34 | sub, err := deliver.SubscribeTx(ctx, channel, txID) 35 | if err != nil { 36 | return errors.Wrapf(err, "%s: failed to subscribe on tx event", mspID) 37 | } 38 | defer func() { _ = sub.Close() }() 39 | 40 | _, err = sub.Result() 41 | return err 42 | } 43 | -------------------------------------------------------------------------------- /client/channel/interface.go: -------------------------------------------------------------------------------- 1 | package channel 2 | -------------------------------------------------------------------------------- /client/channel/list.go: -------------------------------------------------------------------------------- 1 | package channel 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hyperledger/fabric-protos-go/peer" 7 | 8 | "github.com/s7techlab/hlf-sdk-go/api" 9 | "github.com/s7techlab/hlf-sdk-go/client/chaincode" 10 | "github.com/s7techlab/hlf-sdk-go/client/tx" 11 | ) 12 | 13 | type CSCCListGetter struct { 14 | Querier *tx.ProtoQuerier 15 | } 16 | 17 | func NewCSCCListGetter(querier api.Querier) *CSCCListGetter { 18 | return &CSCCListGetter{ 19 | Querier: tx.NewProtoQuerier(querier, ``, chaincode.CSCC), 20 | } 21 | } 22 | 23 | func (g *CSCCListGetter) GetChannels(ctx context.Context) (*peer.ChannelQueryResponse, error) { 24 | res, err := g.Querier.QueryStringsProto(ctx, []string{chaincode.CSCCGetChannels}, &peer.ChannelQueryResponse{}) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return res.(*peer.ChannelQueryResponse), nil 29 | } 30 | -------------------------------------------------------------------------------- /client/deliver/subs/block.go: -------------------------------------------------------------------------------- 1 | package subs 2 | 3 | import ( 4 | "github.com/hyperledger/fabric-protos-go/common" 5 | ) 6 | 7 | type ( 8 | // BlockHandler when block == nil is eq EOF and signal for terminate all sub channels 9 | BlockHandler func(block *common.Block) bool 10 | ReadyForHandling func() 11 | 12 | ErrorCloser interface { 13 | Done() <-chan struct{} 14 | Err() <-chan error 15 | Errors() chan error 16 | Close() error 17 | } 18 | ) 19 | 20 | func NewBlockSubscription() *BlockSubscription { 21 | return &BlockSubscription{ 22 | blocks: make(chan *common.Block), 23 | } 24 | } 25 | 26 | type BlockSubscription struct { 27 | blocks chan *common.Block 28 | ErrorCloser 29 | } 30 | 31 | func (b *BlockSubscription) Blocks() <-chan *common.Block { 32 | return b.blocks 33 | } 34 | 35 | func (b *BlockSubscription) Handler(block *common.Block) bool { 36 | if block == nil { 37 | close(b.blocks) 38 | } else { 39 | select { 40 | case b.blocks <- block: 41 | case <-b.ErrorCloser.Done(): 42 | return true 43 | } 44 | } 45 | 46 | return false 47 | } 48 | 49 | func (b *BlockSubscription) Serve(base ErrorCloser, readyForHandling ReadyForHandling) *BlockSubscription { 50 | b.ErrorCloser = base 51 | readyForHandling() 52 | return b 53 | } 54 | -------------------------------------------------------------------------------- /client/discovery/discovery.go: -------------------------------------------------------------------------------- 1 | package discovery 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | ) 6 | 7 | var ( 8 | ErrNoChannels = errors.New(`channels not found`) 9 | ErrChannelNotFound = errors.New(`channel not found`) 10 | ErrNoChaincodes = errors.New(`no chaincodes on channel`) 11 | ErrUnknownProvider = errors.New(`unknown discovery provider (forgotten import?)`) 12 | ) 13 | 14 | // ServiceDiscoveryType - what types of discovery we support 15 | type ServiceDiscoveryType string 16 | 17 | const ( 18 | LocalConfigServiceDiscoveryType ServiceDiscoveryType = "local" 19 | GossipServiceDiscoveryType ServiceDiscoveryType = "gossip" 20 | ) 21 | -------------------------------------------------------------------------------- /client/errors.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/s7techlab/hlf-sdk-go/client/errors" 5 | ) 6 | 7 | const ( 8 | ErrEmptyConfig = errors.Error(`empty config`) 9 | ErrInvalidPEMStructure = errors.Error(`invalid PEM structure`) 10 | 11 | ErrNoPeersForMSP = errors.Error(`no peers for MSP`) 12 | ErrMSPNotFound = errors.Error(`MSP not found`) 13 | ErrPeerNotReady = errors.Error(`peer not ready`) 14 | ) 15 | -------------------------------------------------------------------------------- /client/errors/error.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // todo: remove 8 | 9 | type Error string 10 | 11 | func (e Error) Error() string { 12 | return string(e) 13 | } 14 | 15 | type ErrNoReadyPeers struct { 16 | MspId string 17 | } 18 | 19 | func (e ErrNoReadyPeers) Error() string { 20 | return fmt.Sprintf("no ready peers for MspId: %s", e.MspId) 21 | } 22 | 23 | type ErrUnexpectedHTTPStatus struct { 24 | Status int 25 | Body []byte 26 | } 27 | 28 | func (err ErrUnexpectedHTTPStatus) Error() string { 29 | return fmt.Sprintf("unexpected HTTP status code: %d with body %s", err.Status, string(err.Body)) 30 | } 31 | -------------------------------------------------------------------------------- /client/errors/multi.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type MultiError struct { 8 | Errors []error 9 | } 10 | 11 | func (e *MultiError) Error() string { 12 | errStr := "next errors occurred:\n" 13 | for _, err := range e.Errors { 14 | errStr += fmt.Sprintf("%s\n", err.Error()) 15 | } 16 | return errStr 17 | } 18 | 19 | func (e *MultiError) Add(err error) { 20 | e.Errors = append(e.Errors, err) 21 | } 22 | -------------------------------------------------------------------------------- /client/grpc/opencensus/hlf/hlf.go: -------------------------------------------------------------------------------- 1 | package hlf 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "go.opencensus.io/plugin/ocgrpc" 8 | "go.opencensus.io/trace" 9 | "google.golang.org/grpc/stats" 10 | ) 11 | 12 | // Wrap easy way for plug-up grpc.StatsHandler and mixing needed annotations to span 13 | func Wrap(statsHandler *ocgrpc.ClientHandler) stats.Handler { 14 | return &wrapper{ 15 | oc: statsHandler, 16 | } 17 | } 18 | 19 | type wrapper struct { 20 | oc *ocgrpc.ClientHandler 21 | } 22 | 23 | func (w *wrapper) TagConn(ctx context.Context, connInfo *stats.ConnTagInfo) context.Context { 24 | if w.oc != nil { 25 | return w.oc.TagConn(ctx, connInfo) 26 | } 27 | 28 | return ctx 29 | } 30 | 31 | func (w *wrapper) HandleConn(ctx context.Context, cs stats.ConnStats) { 32 | if w.oc != nil { 33 | w.oc.HandleConn(ctx, cs) 34 | } 35 | } 36 | 37 | func (w *wrapper) TagRPC(ctx context.Context, rpcInfo *stats.RPCTagInfo) context.Context { 38 | if w.oc != nil { 39 | return w.oc.TagRPC(ctx, rpcInfo) 40 | } 41 | return ctx 42 | } 43 | 44 | func (w *wrapper) HandleRPC(ctx context.Context, rs stats.RPCStats) { 45 | span := trace.FromContext(ctx) 46 | 47 | switch rs := rs.(type) { 48 | case *stats.InHeader: 49 | if rs.RemoteAddr != nil { 50 | span.AddAttributes( 51 | trace.StringAttribute( 52 | "InHeader.RemoteAddr", 53 | rs.RemoteAddr.String(), 54 | ), 55 | ) 56 | } 57 | if rs.LocalAddr != nil { 58 | span.AddAttributes( 59 | trace.StringAttribute( 60 | "InHeader.LocalAddr", 61 | rs.LocalAddr.String(), 62 | ), 63 | ) 64 | } 65 | 66 | span.AddAttributes( 67 | trace.StringAttribute( 68 | "InHeader.Compression", 69 | rs.Compression, 70 | ), 71 | ) 72 | case *stats.OutHeader: 73 | if rs.RemoteAddr != nil { 74 | span.AddAttributes( 75 | trace.StringAttribute( 76 | "OutHeader.RemoteAddr", 77 | rs.RemoteAddr.String(), 78 | ), 79 | ) 80 | } 81 | if rs.LocalAddr != nil { 82 | span.AddAttributes( 83 | trace.StringAttribute( 84 | "OutHeader.LocalAddr", 85 | rs.LocalAddr.String(), 86 | ), 87 | ) 88 | } 89 | 90 | span.AddAttributes( 91 | trace.StringAttribute( 92 | "OutHeader.Compression", 93 | rs.Compression, 94 | ), 95 | ) 96 | } 97 | // sometimes we get cancelled context if further execution(asking peers etc.) isn't necessary 98 | // but request is fully valid, and we don't want to see confusing errors in jaeger 99 | if errors.Is(ctx.Err(), context.Canceled) { 100 | return 101 | } 102 | 103 | if w.oc != nil { 104 | w.oc.HandleRPC(ctx, rs) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/ca/ca.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEtDCCApwCAQAwMTEKMAgGA1UEBhMBQzEKMAgGA1UEBxMBTDEXMBUGA1UEChMO 3 | SExGLVNESy1HTyBUTFMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/ 4 | scxb95I0SFO3AuGQ6OZQx5JOI2ZoTvaHrnSVs56i2xCna1muQLapeRdguUCF84yt 5 | XsfTxrsvpSSSMZzFpZviWtbESW5VOqcoPM/6f/KMlgz/4PgDR+YD4mGjqUnHGgRO 6 | HuLECuZBpZlh9F/dTQOPDHtyw2Aetmck9c9mfCsbJdvFlpZYK6tubMcW6eV7aW62 7 | aevGchZJzEnLEMEb02ReZPkytfVqHC12MEFlrrvsVIieS5kZlmicxhW9uNGQfGez 8 | 1gsWRCO6JJS678530+ieWJe9jWFuCtr3SA780goKmd8aMTCIDCAqPtmDqb7fIOv0 9 | q1t8qTDzqSauSXBbmegn6mQ1oSviwMB5SzkCc61MiosYwQyH3l97BG/LTrjoglBe 10 | azE3XQtAFBrsmSHgdSma35IEhaGO9ffRXU5jocj1qG7e3xtCs5V9kXTZ7ppjR4IB 11 | VMMZa/X7rKHpoVeQ687YnN2W/dHgg0ocQMzbh9hvuWWR54zV2Ti6yCeX+eJwkKLB 12 | 7nt+voeCmLlLIVeuV5OAf/E4j29RNphGxmpV6zi0nmPatk9YxfBKBeTfKLrEDJx6 13 | TtTAmAyc6/sagWuKRFpPEqMwU+wEFQ4HORdV8odTLdO2Vw/qlfc4d+87AeFkTAPF 14 | b7kM78J0hEknozgJiymHudig3jISaEtqlRm7XVEDZQIDAQABoD4wPAYJKoZIhvcN 15 | AQkOMS8wLTAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDwYDVR0TAQH/BAUw 16 | AwEB/zANBgkqhkiG9w0BAQ0FAAOCAgEAm+yDjsOLd9L4bhhY3ERntCVPEa5iKSnk 17 | j+YBw89TK8fsR0yD16oVEPVQ3trCCdpk5wRAatj4JtIN6Iu+eTj94f65XaCpVORX 18 | zbtEhpFpLqcbG9XeCbd1c4+zjyrcH0tASqWAgdTkG0Qa28ukc+nQHoU5m9L90akj 19 | ETgpd7HYIg8iYNeVpjl4XiEDF+UuwBmWQbpS/nmel284nNKip15rcVJ4Gnto1QJ2 20 | q2TTHi6DrkdIm1lBvnwCaWh0Wdsiq62wky9ASni4ALc232iNuSB6BrvSD10qgKzi 21 | zMiJfQL5A7cRH1m+gXs4r3d3jL/t3S3hv6hNZa+j18OM1LsRna09MYoadT803WsA 22 | X+KVnLDBQTlupjYny3wejgqvEOeyvpv6LlCxBMShGEjPlTcgucdXjl9tA6DjhbBB 23 | xiQ6rfwZnoQ49jun8OnJXCPR351nfnWzs+3gIQNExaP3KLO4k4DKndS0erwXWjsM 24 | o1BozBTzgh2ujlQ1MP13jOqWHDG+fJMR35wuUpBuLNtFlTimgsHfDdcPNBsPwNJR 25 | 5lYvEX3ozqI8u8bxq8o7RcyWlbYqqiBpkdXtc1tIRgwA45iWMcxl7RlUpqB2pfRO 26 | 4pPcNpp5+aKJgldd0auDdYd1WQ2jt4VgLRZJoMxBUDcFwAdg/l0USFUXyqRHLZa6 27 | gKFyF5Ub5GA= 28 | -----END CERTIFICATE REQUEST----- 29 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/ca/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFQzCCAyugAwIBAgIUJlWQCzKjfX+2IJmivDsT2F1YW+UwDQYJKoZIhvcNAQEN 3 | BQAwMTEKMAgGA1UEBhMBQzEKMAgGA1UEBxMBTDEXMBUGA1UEChMOSExGLVNESy1H 4 | TyBUTFMwHhcNMjQwNjA0MTIwOTAwWhcNMzQwNjAyMTIwOTAwWjAxMQowCAYDVQQG 5 | EwFDMQowCAYDVQQHEwFMMRcwFQYDVQQKEw5ITEYtU0RLLUdPIFRMUzCCAiIwDQYJ 6 | KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL+xzFv3kjRIU7cC4ZDo5lDHkk4jZmhO 7 | 9oeudJWznqLbEKdrWa5Atql5F2C5QIXzjK1ex9PGuy+lJJIxnMWlm+Ja1sRJblU6 8 | pyg8z/p/8oyWDP/g+ANH5gPiYaOpSccaBE4e4sQK5kGlmWH0X91NA48Me3LDYB62 9 | ZyT1z2Z8Kxsl28WWllgrq25sxxbp5XtpbrZp68ZyFknMScsQwRvTZF5k+TK19Woc 10 | LXYwQWWuu+xUiJ5LmRmWaJzGFb240ZB8Z7PWCxZEI7oklLrvznfT6J5Yl72NYW4K 11 | 2vdIDvzSCgqZ3xoxMIgMICo+2YOpvt8g6/SrW3ypMPOpJq5JcFuZ6CfqZDWhK+LA 12 | wHlLOQJzrUyKixjBDIfeX3sEb8tOuOiCUF5rMTddC0AUGuyZIeB1KZrfkgSFoY71 13 | 99FdTmOhyPWobt7fG0KzlX2RdNnummNHggFUwxlr9fusoemhV5Drztic3Zb90eCD 14 | ShxAzNuH2G+5ZZHnjNXZOLrIJ5f54nCQosHue36+h4KYuUshV65Xk4B/8TiPb1E2 15 | mEbGalXrOLSeY9q2T1jF8EoF5N8ousQMnHpO1MCYDJzr+xqBa4pEWk8SozBT7AQV 16 | Dgc5F1Xyh1Mt07ZXD+qV9zh37zsB4WRMA8VvuQzvwnSESSejOAmLKYe52KDeMhJo 17 | S2qVGbtdUQNlAgMBAAGjUzBRMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD 18 | AQH/MB0GA1UdDgQWBBSxcVpthsBS8ZCGPlFYHM3Sg64xyzAPBgNVHREECDAGhwR/ 19 | AAABMA0GCSqGSIb3DQEBDQUAA4ICAQCB9xohfexSvxa0H89zApyU2RyK6WPhl8RO 20 | ciqtLYh3khSnTXU8AfGMFHc0meRNNn2EKmmtRoWAogftuSmHfHlynbqWZe9mqUy5 21 | mfkuARcJN1X44ngb9DgJhVOBg19TC7OR2Ux/OfCtctfIXNapTNOpAJ0djZ/N/vlk 22 | z6HaxZAkkpGxFVHJTFmoeb44rrXksejjtZcQsdeT5b9anCcQTiL1CETA6+DJtWPk 23 | s3Q96DLX8nZYhCAyTrT+S9SffOvznEWE/qaYG6da7s72ty7gclLbokrqjP/nM5zI 24 | iO4027NmSofiJ615iVPn+GYnrEu8oNlI5omLkoXccj6CqgqZnXC3b1RtyRSyvcFn 25 | iZTomBF0/5PcENGGN2KJ8Py2zVrQxko/jM0pwhLqqZ/wsGUOL0jvskGkod9YtjyS 26 | b0+O67dI2rVdUoUIywP1E6e96wGAjtQzs6avQB/7NOcGueLxdFj/hClXmnn4t/UA 27 | A0oCEqRNwj6mFT9f5vPnQeR38qjcWHad5w7NQ2YSCZEcUMeECL4kvOsaXeKDUs7F 28 | OHAGACLMx65f+o81TWKMndwRWRQJ45lzn8HZiTbfc+m0F8jYJwFBWihFUwZErTdn 29 | gZ/AplRZkXCI76O1QBL9Gat8vtj/y0saYxm7DSKGICJNZBA9pfD2qm/rqE47JNVY 30 | TzadI6R4bw== 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/ca/cfssl.json: -------------------------------------------------------------------------------- 1 | { 2 | "signing": { 3 | "default": { 4 | "expiry": "8760h" 5 | }, 6 | "profiles": { 7 | "server": { 8 | "usages": [ 9 | "signing", 10 | "digital signing", 11 | "key encipherment", 12 | "server auth" 13 | ], 14 | "expiry": "87600h" 15 | }, 16 | "client": { 17 | "usages": [ 18 | "signing", 19 | "digital signature", 20 | "key encipherment", 21 | "client auth" 22 | ], 23 | "expiry": "87600h" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /client/grpc/testdata/tls/ca/csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "CA": { 3 | "expiry": "87600h", 4 | "pathlen": 0 5 | }, 6 | "hosts": [ 7 | "localhost", 8 | "127.0.0.1" 9 | ], 10 | "key": { 11 | "algo": "rsa", 12 | "size": 4096 13 | }, 14 | "names": [ 15 | { 16 | "C": "C", 17 | "L": "L", 18 | "O": "HLF-SDK-GO TLS", 19 | "OU": "", 20 | "ST": "" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /client/grpc/testdata/tls/client/cert.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEkzCCAnsCAQAwTjELMAkGA1UEBhMCUlUxDzANBgNVBAgTBk1vc2NvdzEPMA0G 3 | A1UEBxMGTW9zY293MQswCQYDVQQKEwJTNzEQMA4GA1UECxMHVGVjaExhYjCCAiIw 4 | DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANPCmLhh7iibwkZ1Z9g6G2ZxI/DB 5 | H1iRxH/1eTKiPUXvGMHs0lvQZ+/zQ/6YtG0GPsKeELsT5qIgDe9hoKjozxh3vniY 6 | qlI8z19Z/lGULYvjBqnu+1BNNZUzCuQcB1+4XoVdBvn8FkS30uUvfy/tPdEHW8kl 7 | THuwCyJ+3MH5tC574booulgKmdJzmjwmSINKdSPl6I56U8kRC+At8abgha9H0qCr 8 | Zr1fJ5eeJ5wC5rnsjZY7CMdW8FlLtwwDq5RLCpf6oOTz4ZjqIz2R0T8q70FCrgXK 9 | 1pobLvJE1e9fyovL4oKnp6xbibVdaHKtziY5u1nI7KQBxmRgpzIdYl8jT31W6wb2 10 | t+kQq4e95T8RdTkznrBoh9TW6YuXO+LMt1BGQYT36D9AU3SYQh3XG9C6XjgRxh8t 11 | BWd/Id/27sOFrmfYSUukbMkxzqZfeitrLJlsRWytg0+WDbXT5Wvl+sczfllO0HRQ 12 | y3OQDjcURlWqAnd7scUKtTalLlDsN+6RFCmk20kkpMC51uxe+O1dI2xFadzqR4xe 13 | 8WzHM02ZbOaxXdOY7CRABf8XnBPoIkinQz0F7CzpP26iSs1h0xw5aPqrODrktDIn 14 | RlwGfUqlX4PRsEhBkBtsUPvYcDyFx3ZFGs86MReiqE763DUQLKJVJF1Hfry0cLHS 15 | 4+NZ88W/JEAp2NZzAgMBAAGgADANBgkqhkiG9w0BAQ0FAAOCAgEAJx1UqYLOnFMA 16 | Gr75om1NqHj+8PxanTIhuJz6EULnpYkJGezqHCHkZy9mN40nPWOIg8+RMOCZkQ8X 17 | diiLuZQzH7uNRi701rb18DQEK1WeTSEfQuCjnrqss8tspH2GHJc7d4ImjRnvia2N 18 | E/KS30ms7xmOQeBAJAGVG30vf1lvJ8OYkS6RhRW3d80n/vXaTsT0HEb9ief78Jps 19 | s1/3HRKmr/3oA/753CTdsl/gLfpHwemNTv6aiwuE35B1jgK2o7Ln/CzSOh5sWLj8 20 | yZ/hu5FBt51MGL1+xWI1ghXYsVW/LEn421itCmsmH/P4GakOGLGafXdjBn6vqBw+ 21 | UjCcPk+0XtPYLXQ640eZxgaOzT5uUr4bIFurfmvnEVWCRcuu4bf2tN+UKLWDw95I 22 | zeQh8J473W4zq6ofEGq1ZGScUFP6E3Y9MVJQy9em67Q2u/IE2nCLODFdEIQmW8xv 23 | GXmpTMuNKaKf8qTDiNRpVNEm0LepVNeb5WqJ8tEyhav+256Zodn66TI0EdhsJq6n 24 | APonLNaISBt4niRHApz8HxLFpy4p2u0OOXJmpvy9NaVldAtJPC/hCbwcVeppGv9E 25 | Hr7AgkAtIYgmAb5IyvzL28jDN2OJvaTobN/ou/vEsm/wq7Czy2+rDKPL2tKqP5tJ 26 | NRLUqHrMvzCm6Q9V2TacbY7M1H+N8RE= 27 | -----END CERTIFICATE REQUEST----- 28 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/client/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFgjCCA2qgAwIBAgIUWRYZaPdeDIm/xs27i8Y5NqCJB+owDQYJKoZIhvcNAQEN 3 | BQAwMTEKMAgGA1UEBhMBQzEKMAgGA1UEBxMBTDEXMBUGA1UEChMOSExGLVNESy1H 4 | TyBUTFMwHhcNMjQwNjA0MTIxNDAwWhcNMzQwNjAyMTIxNDAwWjBOMQswCQYDVQQG 5 | EwJSVTEPMA0GA1UECBMGTW9zY293MQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAoT 6 | AlM3MRAwDgYDVQQLEwdUZWNoTGFiMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC 7 | CgKCAgEA08KYuGHuKJvCRnVn2DobZnEj8MEfWJHEf/V5MqI9Re8YwezSW9Bn7/ND 8 | /pi0bQY+wp4QuxPmoiAN72GgqOjPGHe+eJiqUjzPX1n+UZQti+MGqe77UE01lTMK 9 | 5BwHX7hehV0G+fwWRLfS5S9/L+090QdbySVMe7ALIn7cwfm0Lnvhuii6WAqZ0nOa 10 | PCZIg0p1I+XojnpTyREL4C3xpuCFr0fSoKtmvV8nl54nnALmueyNljsIx1bwWUu3 11 | DAOrlEsKl/qg5PPhmOojPZHRPyrvQUKuBcrWmhsu8kTV71/Ki8vigqenrFuJtV1o 12 | cq3OJjm7WcjspAHGZGCnMh1iXyNPfVbrBva36RCrh73lPxF1OTOesGiH1Nbpi5c7 13 | 4sy3UEZBhPfoP0BTdJhCHdcb0LpeOBHGHy0FZ38h3/buw4WuZ9hJS6RsyTHOpl96 14 | K2ssmWxFbK2DT5YNtdPla+X6xzN+WU7QdFDLc5AONxRGVaoCd3uxxQq1NqUuUOw3 15 | 7pEUKaTbSSSkwLnW7F747V0jbEVp3OpHjF7xbMczTZls5rFd05jsJEAF/xecE+gi 16 | SKdDPQXsLOk/bqJKzWHTHDlo+qs4OuS0MidGXAZ9SqVfg9GwSEGQG2xQ+9hwPIXH 17 | dkUazzoxF6KoTvrcNRAsolUkXUd+vLRwsdLj41nzxb8kQCnY1nMCAwEAAaN1MHMw 18 | DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQC 19 | MAAwHQYDVR0OBBYEFHKZn2girV/x5msPdUIhy+oYYkn3MB8GA1UdIwQYMBaAFLFx 20 | Wm2GwFLxkIY+UVgczdKDrjHLMA0GCSqGSIb3DQEBDQUAA4ICAQCSfUDk9So//W6s 21 | RLfugorV8buxlUxm7y5iQatgFtjcEUiYLDLGRyCwMz6omDgSFwGk5N4YfXKjrJiF 22 | /0Y95v4ezIg+GCS9CGm5T5hJU5ZyzLu2viJwWos5TGzu7v/pHxlQT6fkX1xUzuAg 23 | sbUptOnCgVgkT4Obcj5ThZmiuKIrHGAW6nFNbeG4l1XhXB83D9ysRwhlOYZ+e8Wb 24 | lDi0K7gvp/VtR+FDwDi23IMarLqik+4ljnfce9rdBukqbe/wrXmKVTMTGt79dHao 25 | DRARFM3mZ/ifVKZpkX4NKiqpCBvIBju8CWQhOYw+OVLAapgwpJA/EDghK07q39T1 26 | 20dHP0+mAQIKp3lu2qLGzWkCtMt27RJFWQrlGkrQF3Prnvp2ulz3pU1qDy2eNCph 27 | 1BFT0PusbMpZz/gauNrmumiDBdtZiUSopcaQVj5k72MhvizZBhRy9KPLoRxXbFgm 28 | tmiDFaFw83shwtfpHMMrF/ysgeAX6F/xn9vIAuC3QC7RMkpRYUTHoadlrXLfodQP 29 | OndgSW5VW0A9unHrEKaNWdjUC6FJuNi9wNi0Wo0H5nqfswH2mkOvC+sK1DGsxdBm 30 | CfYbS/+szVNxF5uP5fMUhSM0fOioxZUmAdbe40iJVvosLnev2UJtkEekSyQRxNRw 31 | 8nTaD+40ezZdpSdbirhlFwIaROgaMA== 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/client/csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosts": [], 3 | "key": { 4 | "algo": "rsa", 5 | "size": 4096 6 | }, 7 | "names": [ 8 | { 9 | "C": "RU", 10 | "L": "Moscow", 11 | "O": "S7", 12 | "OU": "TechLab", 13 | "ST": "Moscow" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /client/grpc/testdata/tls/readme.md: -------------------------------------------------------------------------------- 1 | # Install https://github.com/cloudflare/cfssl 2 | 3 | ## Issue CA cert 4 | 5 | ``` 6 | cd ./ca && cfssl genkey -initca csr.json | cfssljson -bare ca 7 | ``` 8 | 9 | ## Issue client certificate 10 | 11 | ``` 12 | (cd ./client && cfssl gencert -ca ../ca/ca.pem -ca-key ../ca/ca-key.pem -config ../ca/cfssl.json -profile client csr.json | cfssljson -bare) 13 | ``` 14 | 15 | ## Issue server certificate 16 | 17 | ``` 18 | (cd ./server && cfssl gencert -ca ../ca/ca.pem -ca-key ../ca/ca-key.pem -config ../ca/cfssl.json -profile server csr.json | cfssljson -bare) 19 | ``` -------------------------------------------------------------------------------- /client/grpc/testdata/tls/server/cert.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIEwDCCAqgCAQAwTjELMAkGA1UEBhMCUlUxDzANBgNVBAgTBk1vc2NvdzEPMA0G 3 | A1UEBxMGTW9zY293MQswCQYDVQQKEwJTNzEQMA4GA1UECxMHVGVjaExhYjCCAiIw 4 | DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOn/EDrgiyePyGnfNdxCq3pirzzM 5 | 8VG6Y8kU2jVcCeJ6t2C9ASmUq/ayS+81/i16uXIi1XkNxNWoxKq6u2sugk+gId8h 6 | w9vCQ5K4PN+H897OkdXv4qajXJ2ct+CNFN6trtQwrZDVX5TJTqPQWHXYiLy2f3iN 7 | NHSzr0LdWe+8lC5UpWf/mVFfRXJIuyjRxZ0nMF0NPEAOuTKlEwMGHs/GRaSWRHA/ 8 | pQPJ7LWznJDKvcA5xU3rCqOgwBZfpZP5JK/rIPdc/EupYR+BWOVqQkALtwEnqHe/ 9 | Wyhd1Yr0n6c9kXltxMqb0LiyrFdBbuiHrSpPsPzI/5pAxXXOvSe7aN3/mLMXtTmS 10 | uPGJ8g23o/iunHm+FoPo6aKjHQVLUueHakZR9+M/cT1e4BEu4uETYEikE2TwsZcC 11 | sqL+TJwgnjbtYNFSaX930+s8j2aQqPlGqOoUsdb9DPxWg/YOqnm/fiomW5yb9eRl 12 | Nws7JNzPolq+fZ6SMiWTAtAbsrJ05vzlu2cWqux7KAUeB0D0aAOGEzeVLbvZNzcG 13 | Dm7ElpZHrozY2qJImc92lfBgqwa9CqN1GGVDtEzQ1DZyf/ymvjklp3bFQKTUnkRp 14 | r4dGEnk7irjXxGmffRImGuII9LWQG2ZFy0MgJjwq6Ra42fcoXjoycD2DjrZVgCt/ 15 | s2XrzgckVi9w8j03AgMBAAGgLTArBgkqhkiG9w0BCQ4xHjAcMBoGA1UdEQQTMBGC 16 | CWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQ0FAAOCAgEAPTi38s1InCLWpAeA 17 | RVC5aEBOYjHSpgDTuHtbBPf/PEauK+00h35ZfO4WRhzcemBieI6cKlWZ33vvK905 18 | 0m/rbdX+mrvm38QDsI0im5KS63iOGc3Po75e4xdfBH0/iiYDA5I6H896O6Pv1Bg/ 19 | 99v7gMLu1u8gnX6ycIbwmpbMWhqclZa0XcxF+l+WoCOFwAlXHZDrTzDRwO8/MPGA 20 | CmL42OOsHai/EGpL9rjiXcTWEBE2fDu3MriGVsCh6XSe0HbkdMsGKzYP0t6op5YR 21 | hSFWeIN6YEHfZnKrAsMwJmbBUxKMdzU9D37BtkMcN/BSoizyGDXXS5rf3qyZehhI 22 | jeqBhUnaUqO3gdnIAQUnbT/YPPdA8ouRo+xumixrZwPu8GxuucIOq6tzznC+3jGI 23 | YyZZVUmvS0bzYAYItgJiD+AD+/6HE7za+N6b4JvXevTYCYPBMxpvSHYbV2WuF1yq 24 | rt2FT3ZOSq5/BjaBF96bxIZQAGYCCe9B6DAShmiyGGdKHE3FZe8UNGmYYkDinS5I 25 | tKwRxVyLAgzKPstWyvh947U/746DRy35ENHxfgF/jrvsuiqt55elCYKWIqryPg3L 26 | 0X8cXkqN39aAAUwd6C7R/f0i7NqMtc4ejKzvdj/Ts1kdCPlzW0E7UT3b5a9x8vO7 27 | PCEtPXDcru+7FGqJbpbEUzSVU6E= 28 | -----END CERTIFICATE REQUEST----- 29 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/server/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFoDCCA4igAwIBAgIURW1B4mjJTUQCgNOj1+9+Gl2ge+wwDQYJKoZIhvcNAQEN 3 | BQAwMTEKMAgGA1UEBhMBQzEKMAgGA1UEBxMBTDEXMBUGA1UEChMOSExGLVNESy1H 4 | TyBUTFMwHhcNMjQwNjA0MTIxNTAwWhcNMzQwNjAyMTIxNTAwWjBOMQswCQYDVQQG 5 | EwJSVTEPMA0GA1UECBMGTW9zY293MQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAoT 6 | AlM3MRAwDgYDVQQLEwdUZWNoTGFiMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC 7 | CgKCAgEA6f8QOuCLJ4/Iad813EKremKvPMzxUbpjyRTaNVwJ4nq3YL0BKZSr9rJL 8 | 7zX+LXq5ciLVeQ3E1ajEqrq7ay6CT6Ah3yHD28JDkrg834fz3s6R1e/ipqNcnZy3 9 | 4I0U3q2u1DCtkNVflMlOo9BYddiIvLZ/eI00dLOvQt1Z77yULlSlZ/+ZUV9Fcki7 10 | KNHFnScwXQ08QA65MqUTAwYez8ZFpJZEcD+lA8nstbOckMq9wDnFTesKo6DAFl+l 11 | k/kkr+sg91z8S6lhH4FY5WpCQAu3ASeod79bKF3VivSfpz2ReW3EypvQuLKsV0Fu 12 | 6IetKk+w/Mj/mkDFdc69J7to3f+Ysxe1OZK48YnyDbej+K6ceb4Wg+jpoqMdBUtS 13 | 54dqRlH34z9xPV7gES7i4RNgSKQTZPCxlwKyov5MnCCeNu1g0VJpf3fT6zyPZpCo 14 | +Uao6hSx1v0M/FaD9g6qeb9+KiZbnJv15GU3Czsk3M+iWr59npIyJZMC0BuysnTm 15 | /OW7Zxaq7HsoBR4HQPRoA4YTN5Utu9k3NwYObsSWlkeujNjaokiZz3aV8GCrBr0K 16 | o3UYZUO0TNDUNnJ//Ka+OSWndsVApNSeRGmvh0YSeTuKuNfEaZ99EiYa4gj0tZAb 17 | ZkXLQyAmPCrpFrjZ9yheOjJwPYOOtlWAK3+zZevOByRWL3DyPTcCAwEAAaOBkjCB 18 | jzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/ 19 | BAIwADAdBgNVHQ4EFgQUthvqH9r2VCMd8MYQbKjImT5N+vEwHwYDVR0jBBgwFoAU 20 | sXFabYbAUvGQhj5RWBzN0oOuMcswGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAAB 21 | MA0GCSqGSIb3DQEBDQUAA4ICAQB9KA/4Fb0PM+O/QqIJ2Ble50GI/a4JWHLYWJBC 22 | F1Ey3RacLyuvw9jN+S/ABsbxpVJvCPu/IT8jM+JAkkXjaquvVKwEHdq8i+cEEoqe 23 | kOWAYGbS1i5Ru9a16gn6AY9gimvyYPM0eGaYBJO5rxCDMkCXKMmha90I/VRBKGD0 24 | iAQSeTniKT/dftFQ571+SS3oitizc9T75NuXdY50kPFzKNuEgaDolE1CZ843k97s 25 | xBiqZsTcrx6+g8UxfHit052uxs8N0WISU+eYHNYF/vFidRz0KmwJ4YRaqrXpYiIy 26 | nd5VnHOzUzpPVDUwk51pcXNeehdqtkLa/THD49m3HAia9mOqEcI4xMH9ZpNL25Xc 27 | ETLQev4/F7Yf/Dst3Igf0e3YPu7+AUff/tN8wUyb6fxCkx65qqNQHWdDYfRg0/Ez 28 | 63H51zTTqhAtImA/+ZqjvOC0ST54tM6LYPk5sI8KuX0rLI1QRDXzdCDTKdmWmj1c 29 | pNXarX1MzmTUAY2Y94guLqgIsNooIt6EqCZ+WKMrrXwTmz1WujUm9b1X0c5fwcTn 30 | wB5JMWksDy6Efpp8vRSl0C3jpu1jus4/4nxPNr8HoXlhzEK0jzYumzFVV06VdaYs 31 | AzLGlpXuiC5uP+pdW5R3O0jNfcBPZBBJqPXG+HBuCFGrTyvVXlepnmyXBDHy9TxJ 32 | +8YnrQ== 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /client/grpc/testdata/tls/server/csr.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosts": [ 3 | "localhost", 4 | "127.0.0.1" 5 | ], 6 | "key": { 7 | "algo": "rsa", 8 | "size": 4096 9 | }, 10 | "names": [ 11 | { 12 | "C": "RU", 13 | "L": "Moscow", 14 | "O": "S7", 15 | "OU": "TechLab", 16 | "ST": "Moscow" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /client/logger.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import "go.uber.org/zap" 4 | 5 | var DefaultLogger, _ = zap.NewDevelopment() 6 | -------------------------------------------------------------------------------- /client/tx/args.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/golang/protobuf/proto" 8 | ) 9 | 10 | var ( 11 | ErrUnknownArgType = errors.New(`unknown arg type`) 12 | ) 13 | 14 | func FnArgs(fn string, args ...[]byte) [][]byte { 15 | var argsBytes [][]byte 16 | 17 | if fn != `` { 18 | argsBytes = append(argsBytes, []byte(fn)) 19 | } 20 | 21 | return append(argsBytes, args...) 22 | } 23 | 24 | func ArgBytes(arg interface{}) ([]byte, error) { 25 | switch val := arg.(type) { 26 | 27 | case []byte: 28 | return val, nil 29 | 30 | case string: 31 | return []byte(val), nil 32 | 33 | case proto.Message: 34 | res, err := proto.Marshal(val) 35 | if err != nil { 36 | return nil, fmt.Errorf(`marshal proto arg: %w`, err) 37 | } 38 | 39 | return res, nil 40 | 41 | default: 42 | return nil, ErrUnknownArgType 43 | } 44 | } 45 | 46 | func StringArgsBytes(args ...string) [][]byte { 47 | var argsBytes [][]byte 48 | 49 | for _, arg := range args { 50 | argsBytes = append(argsBytes, []byte(arg)) 51 | } 52 | 53 | return argsBytes 54 | } 55 | 56 | func ArgsBytes(args ...interface{}) ([][]byte, error) { 57 | var argsBytes [][]byte 58 | 59 | for pos, arg := range args { 60 | 61 | converted, err := ArgBytes(arg) 62 | if err != nil { 63 | return nil, fmt.Errorf(`args[%d]: %w`, pos, err) 64 | } 65 | 66 | argsBytes = append(argsBytes, converted) 67 | } 68 | 69 | return argsBytes, nil 70 | } 71 | -------------------------------------------------------------------------------- /client/tx/endorsement.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/hyperledger/fabric-protos-go/common" 8 | "github.com/hyperledger/fabric-protos-go/peer" 9 | "github.com/hyperledger/fabric/msp" 10 | 11 | "github.com/s7techlab/hlf-sdk-go/block" 12 | ) 13 | 14 | var ( 15 | ErrSignerNotDefined = errors.New(`signer not defined`) 16 | ErrChaincodeNotDefined = errors.New(`chaincode not defined`) 17 | ) 18 | 19 | type Endorsement struct { 20 | Channel string 21 | Chaincode string 22 | Args [][]byte 23 | Signer msp.SigningIdentity 24 | TransientMap map[string][]byte 25 | } 26 | 27 | func (e Endorsement) SignedProposal() (signedProposal *peer.SignedProposal, txID string, err error) { 28 | return NewEndorsementSignedProposal(e.Channel, e.Chaincode, e.Args, e.Signer, e.TransientMap) 29 | } 30 | 31 | func NewEndorsementSignedProposal( 32 | channel, chaincode string, args [][]byte, signer msp.SigningIdentity, transientMap map[string][]byte) ( 33 | signedProposal *peer.SignedProposal, txID string, err error) { 34 | 35 | if chaincode == `` { 36 | return nil, ``, ErrChaincodeNotDefined 37 | } 38 | if signer == nil { 39 | return nil, ``, ErrSignerNotDefined 40 | } 41 | 42 | signerSerialized, err := signer.Serialize() 43 | if err != nil { 44 | return nil, ``, fmt.Errorf(`serialize signer: %w`, err) 45 | } 46 | 47 | txParams, err := GenerateParamsForSerializedIdentity(signerSerialized) 48 | if err != nil { 49 | return nil, ``, fmt.Errorf(`tx id: %w`, err) 50 | } 51 | 52 | header, err := block.NewMarshalledCommonHeader( 53 | common.HeaderType_ENDORSER_TRANSACTION, 54 | txParams.ID, 55 | txParams.Nonce, 56 | txParams.Timestamp, 57 | signerSerialized, 58 | channel, 59 | chaincode, 60 | nil) 61 | if err != nil { 62 | return nil, ``, fmt.Errorf(`tx header: %w`, err) 63 | } 64 | 65 | proposal, err := block.NewMarshaledPeerProposal(header, chaincode, args, transientMap) 66 | if err != nil { 67 | return nil, ``, fmt.Errorf(`proposal: %w`, err) 68 | } 69 | 70 | signedProposal, err = block.NewPeerSignedProposal(proposal, signer) 71 | return signedProposal, txParams.ID, err 72 | } 73 | -------------------------------------------------------------------------------- /client/tx/id.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "fmt" 7 | 8 | "github.com/golang/protobuf/ptypes" 9 | "github.com/golang/protobuf/ptypes/timestamp" 10 | "github.com/hyperledger/fabric/msp" 11 | 12 | "github.com/s7techlab/hlf-sdk-go/crypto" 13 | ) 14 | 15 | type Params struct { 16 | ID string 17 | Nonce []byte 18 | Timestamp *timestamp.Timestamp 19 | } 20 | 21 | func GenerateParams(creator msp.SigningIdentity) (*Params, error) { 22 | serialized, err := creator.Serialize() 23 | if err != nil { 24 | return nil, fmt.Errorf(`serialize identity: %w`, err) 25 | } 26 | 27 | return GenerateParamsForSerializedIdentity(serialized) 28 | } 29 | 30 | func GenerateParamsForSerializedIdentity(creator []byte) (*Params, error) { 31 | id, nonce, err := GenerateIDForSerializedIdentity(creator) 32 | if err != nil { 33 | return nil, fmt.Errorf(`tx id: %w`, err) 34 | } 35 | 36 | return &Params{ 37 | ID: id, 38 | Nonce: nonce, 39 | Timestamp: TimestampNow(), 40 | }, nil 41 | } 42 | 43 | func GenerateID(creator msp.SigningIdentity) (id string, nonce []byte, err error) { 44 | serialized, err := creator.Serialize() 45 | if err != nil { 46 | return ``, nil, fmt.Errorf(`serialize identity: %w`, err) 47 | } 48 | 49 | return GenerateIDForSerializedIdentity(serialized) 50 | } 51 | 52 | func GenerateIDForSerializedIdentity(creator []byte) (id string, nonce []byte, err error) { 53 | if nonce, err = crypto.RandomBytes(24); err != nil { 54 | return ``, nil, fmt.Errorf(`get tx nonce: %w`, err) 55 | } 56 | 57 | f := sha256.New() 58 | f.Write(append(nonce, creator...)) 59 | return hex.EncodeToString(f.Sum(nil)), nonce, nil 60 | } 61 | 62 | func TimestampNow() *timestamp.Timestamp { 63 | return ptypes.TimestampNow() 64 | } 65 | -------------------------------------------------------------------------------- /client/tx/proto_invoke.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "reflect" 7 | 8 | "github.com/golang/protobuf/proto" 9 | 10 | "github.com/s7techlab/hlf-sdk-go/api" 11 | ) 12 | 13 | func InvokeProto(ctx context.Context, invoker api.Invoker, channel, chaincode string, args []interface{}, target proto.Message) (proto.Message, error) { 14 | argsBytes, err := ArgsBytes(args...) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | return InvokeBytesProto(ctx, invoker, channel, chaincode, argsBytes, target) 20 | } 21 | 22 | func InvokeStringsProto(ctx context.Context, invoker api.Invoker, channel, chaincode string, args []string, target proto.Message) (proto.Message, error) { 23 | return InvokeBytesProto(ctx, invoker, channel, chaincode, StringArgsBytes(args...), target) 24 | } 25 | 26 | func InvokeBytesProto(ctx context.Context, invoker api.Invoker, channel, chaincode string, args [][]byte, target proto.Message) (proto.Message, error) { 27 | res, _, err := invoker.Invoke( 28 | ctx, channel, chaincode, args, nil, nil, ``) 29 | 30 | if err != nil { 31 | return nil, fmt.Errorf(`invoke channel=%s chaincode=%s: %w`, channel, chaincode, err) 32 | } 33 | 34 | resProto := proto.Clone(target) 35 | 36 | if err = proto.Unmarshal(res.Payload, resProto); err != nil { 37 | return nil, fmt.Errorf(`unmarshal invoke result to %s: %w`, reflect.TypeOf(target), err) 38 | } 39 | 40 | return resProto, nil 41 | } 42 | -------------------------------------------------------------------------------- /client/tx/seek_block.go: -------------------------------------------------------------------------------- 1 | package tx 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/hyperledger/fabric-protos-go/common" 8 | "github.com/hyperledger/fabric-protos-go/orderer" 9 | "github.com/hyperledger/fabric/msp" 10 | 11 | "github.com/s7techlab/hlf-sdk-go/block" 12 | ) 13 | 14 | type SeekBlock struct { 15 | Channel string 16 | Signer msp.SigningIdentity 17 | 18 | Start *orderer.SeekPosition 19 | Stop *orderer.SeekPosition 20 | } 21 | 22 | func (sb SeekBlock) CreateEnvelope() (*common.Envelope, error) { 23 | return NewSeekBlockEnvelope(sb.Channel, sb.Signer, sb.Start, sb.Stop, nil) 24 | } 25 | 26 | func NewSeekGenesisEnvelope(channel string, signer msp.SigningIdentity, tlsCertHash []byte) (*common.Envelope, error) { 27 | start := block.NewSeekSpecified(0) 28 | stop := block.NewSeekSpecified(0) 29 | 30 | return NewSeekBlockEnvelope(channel, signer, start, stop, tlsCertHash) 31 | } 32 | 33 | func NewSeekBlockEnvelope(channel string, signer msp.SigningIdentity, start, stop *orderer.SeekPosition, tlsCertHash []byte) ( 34 | *common.Envelope, error) { 35 | if signer == nil { 36 | return nil, errors.New(`signer should be defined`) 37 | } 38 | signerSerialized, err := signer.Serialize() 39 | if err != nil { 40 | return nil, fmt.Errorf(`serialize signer: %w`, err) 41 | } 42 | 43 | txParams, err := GenerateParamsForSerializedIdentity(signerSerialized) 44 | if err != nil { 45 | return nil, fmt.Errorf(`tx id: %w`, err) 46 | } 47 | 48 | seekInfo, err := block.NewMarshalledSeekInfo(start, stop) 49 | if err != nil { 50 | return nil, fmt.Errorf(`seekInfo: %w`, err) 51 | } 52 | 53 | header, err := block.NewCommonHeader( 54 | common.HeaderType_DELIVER_SEEK_INFO, 55 | txParams.ID, 56 | txParams.Nonce, 57 | txParams.Timestamp, 58 | signerSerialized, 59 | channel, ``, 60 | tlsCertHash) 61 | if err != nil { 62 | return nil, fmt.Errorf(`payload header: %w`, err) 63 | } 64 | 65 | payload, err := block.NewMarshalledCommonPayload(header, seekInfo) 66 | if err != nil { 67 | return nil, fmt.Errorf(`common payload: %w`, err) 68 | } 69 | 70 | return block.NewCommonEnvelope(payload, signer) 71 | } 72 | -------------------------------------------------------------------------------- /cmd/ccpackage/README.md: -------------------------------------------------------------------------------- 1 | # CCPackage CLI example 2 | 3 | ``` 4 | go run main.go \ 5 | --repo=https://github.com/hyperledger-labs/cckit \ 6 | --version=main --name=cars \ 7 | --chaincodePath=github.com/hyperledger-labs/cckit \ 8 | --binaryPath=examples/cars/bin/cars \ 9 | --fabricVersion=FABRIC_V2_LIFECYCLE 10 | ``` 11 | 12 | ``` 13 | go run main.go \ 14 | --repo=https://github.com/hyperledger/fabric-samples \ 15 | --version=main \ 16 | --name=asset-transfer-abac \ 17 | --chaincodePath=github.com/hyperledger/fabric-samples \ 18 | --binaryPath=asset-transfer-abac/chaincode-go \ 19 | --fabricVersion=FABRIC_V2_LIFECYCLE 20 | ``` 21 | 22 | 23 | -------------------------------------------------------------------------------- /cmd/ccpackage/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "go.uber.org/zap" 10 | 11 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage" 12 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage/fetcher" 13 | dockerpacker "github.com/s7techlab/hlf-sdk-go/service/ccpackage/packer/docker" 14 | ) 15 | 16 | func main() { 17 | spec := &ccpackage.PackageSpec{ 18 | Id: &ccpackage.PackageID{}, 19 | } 20 | flag.StringVar(&spec.Id.Name, `name`, ``, `chaincode name`) 21 | flag.StringVar(&spec.Repository, `repo`, ``, `chaincode repo`) 22 | fabricVersion := flag.String(`fabricVersion`, ``, 23 | `fabric version (FABRIC_V1, FABRIC_V2, fFABRIC_V2_LIFECYCLE`) 24 | flag.StringVar(&spec.ChaincodePath, `chaincodePath`, ``, `chaincode path`) 25 | flag.StringVar(&spec.Id.Version, `version`, ``, `chaincode version`) 26 | flag.StringVar(&spec.BinaryPath, `binaryPath`, ``, `binaryPath`) 27 | 28 | flag.Parse() 29 | if *fabricVersion != `` { 30 | if enumVersion, ok := ccpackage.FabricVersion_value[*fabricVersion]; ok { 31 | spec.Id.FabricVersion = ccpackage.FabricVersion(enumVersion) 32 | } else { 33 | fmt.Println(`unknown fabric version: `, *fabricVersion) 34 | os.Exit(1) 35 | } 36 | } 37 | 38 | if err := spec.Validate(); err != nil { 39 | fmt.Println(err) 40 | os.Exit(1) 41 | } 42 | var ( 43 | logger, _ = zap.NewDevelopment() 44 | ctx = context.Background() 45 | ) 46 | 47 | tar, err := fetcher.Fetch(ctx, spec.Repository, spec.Id.Version, logger) 48 | if err != nil { 49 | logger.Fatal(err.Error()) 50 | } 51 | 52 | logger.Info(`package repository source code`, zap.Int(`size`, len(tar))) 53 | 54 | packer := dockerpacker.New(logger) 55 | pkg, err := packer.PackFromTar(ctx, spec, tar) 56 | if err != nil { 57 | logger.Fatal(err.Error()) 58 | } 59 | 60 | fmt.Println(pkg) 61 | } 62 | -------------------------------------------------------------------------------- /crypto/interface.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/x509" 5 | ) 6 | 7 | // Suite describes common cryptographic operations 8 | type Suite interface { 9 | // Sign is used for signing message by presented private key 10 | Sign(msg []byte, key interface{}) ([]byte, error) 11 | // Verify is used for verifying signature for presented message and public key 12 | Verify(publicKey interface{}, msg, sig []byte) error 13 | // Hash is used for hashing presented data 14 | Hash(data []byte) []byte 15 | // NewPrivateKey generates new private key 16 | NewPrivateKey() (interface{}, error) 17 | // GetSignatureAlgorithm returns signature algorithm 18 | GetSignatureAlgorithm() x509.SignatureAlgorithm 19 | } 20 | -------------------------------------------------------------------------------- /crypto/random.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/rand" 5 | ) 6 | 7 | // RandomBytes returns slice of random bytes of presented size 8 | func RandomBytes(length int) ([]byte, error) { 9 | b := make([]byte, length) 10 | _, err := rand.Read(b) 11 | if err != nil { 12 | return nil, err 13 | } 14 | return b, nil 15 | } 16 | -------------------------------------------------------------------------------- /crypto/suite.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | 6 | "github.com/s7techlab/hlf-sdk-go/crypto/ecdsa" 7 | ) 8 | 9 | type Config struct { 10 | Type string `yaml:"type"` 11 | Options map[string]string `yaml:"options"` 12 | } 13 | 14 | var ( 15 | ErrUnknown = errors.New(`unknown`) 16 | ErrTypeRequired = errors.New(`type required`) 17 | 18 | DefaultConfig = &Config{ 19 | Type: ecdsa.Module, 20 | Options: ecdsa.DefaultOpts, 21 | } 22 | 23 | DefaultSuite, _ = NewSuiteByConfig(DefaultConfig, false) 24 | ) 25 | 26 | func NewSuite(name string, opts map[string]string) (Suite, error) { 27 | switch name { 28 | case ecdsa.Module: 29 | return ecdsa.New(opts) 30 | 31 | default: 32 | return nil, ErrUnknown 33 | } 34 | } 35 | 36 | func NewSuiteByConfig(config *Config, useDefault bool) (Suite, error) { 37 | if useDefault && config == nil { 38 | config = DefaultConfig 39 | } 40 | 41 | if config.Type == `` { 42 | return nil, ErrTypeRequired 43 | } 44 | 45 | return NewSuite(config.Type, config.Options) 46 | } 47 | -------------------------------------------------------------------------------- /examples/caclient/config.yaml: -------------------------------------------------------------------------------- 1 | host: http://localhost:7054 2 | 3 | crypto: 4 | type: ecdsa 5 | options: 6 | # Possible curves: P256, P384, P512 7 | curve: P256 8 | # TODO 9 | # Possible algorithms for signature: (not implemented) 10 | signatureAlgorithm: SHA256 11 | # Possible hashing algorithms: SHA2-256, SHA2-384, SHA3-256, SHA3-384 12 | hash: SHA2-256 13 | 14 | -------------------------------------------------------------------------------- /examples/cc_call/README.md: -------------------------------------------------------------------------------- 1 | ### Blockchain Info 2 | 3 | Example allows to get infomation about joined channels and channel's ledger. 4 | 5 | #### Required environment variables 6 | - **MSP_ID** - MSP identifier 7 | - **CONFIG_PATH** - path to configuration file of SDK _(eg. config.yaml)_ 8 | - **CERT_PATH** - path to certificate file of identity _(eg. signcerts/cert.pem)_ 9 | - **KEY_PATH** - path to private key of identity _(eg. keystore/your_pk)_ 10 | 11 | #### Usage 12 | Run with environment variables described above: 13 | ```bash 14 | go run main.go 15 | ``` 16 | 17 | Example output: 18 | ```bash 19 | Fetching info about channel: channel1 20 | Block length: 1, last block: hSUcm1BXeBFUDkYoktP2snFh2sdMtrO7Wn4e381Dq4Y=, prev block: 21 | Fetching info about channel: channel2 22 | Block length: 2, last block: NJdmpdTjGZG3NDfJKWD1qUsNWs2DI/eQnCRBRrioVKo=, prev block: 6vm07LCMvpIjJ9OZ54WJZfZNKZ21w2KbSkEVExjvfN4= 23 | Fetching info about channel: channel3 24 | Block length: 1, last block: eX8As3kxjTbep4QMCGuzj/wrZQQhNlMNTS+zGOBd+lk=, prev block: 25 | ``` -------------------------------------------------------------------------------- /examples/cc_call/cc_call.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/s7techlab/hlf-sdk-go/client" 8 | "github.com/s7techlab/hlf-sdk-go/identity" 9 | ) 10 | 11 | func main() { 12 | 13 | signer, err := identity.NewSigningFromFile( 14 | "Org1MSP", 15 | // PROVIDE YOUR OWN PATHS 16 | "../../../../github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/cert.pem", 17 | "../../../../github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/02a48982a93c9a1fbf7e9702f82d14578aef9662362346ecfe8b3cde50da6799_sk", 18 | ) 19 | if err != nil { 20 | log.Fatalf("connection.invoke: %v", err) 21 | } 22 | 23 | core, err := client.New(context.Background(), 24 | client.WithSigner(signer), client.WithConfigYaml("./cfg.yaml")) 25 | if err != nil { 26 | log.Fatalf("create client core: %v", err) 27 | } 28 | cc, err := core.Channel("mychannel").Chaincode(context.Background(), "basic") 29 | if err != nil { 30 | log.Fatalf("connection.Channel: %v", err) 31 | } 32 | 33 | res, tx, err := cc.Invoke("UpdateAsset"). 34 | ArgString("asset1", "COLOR", "1337", "OWNER", "228"). 35 | Do(context.Background()) 36 | if err != nil { 37 | log.Fatalf("connection.invoke: %v", err) 38 | } 39 | 40 | log.Print("Invoked: ", tx, res) 41 | 42 | res2, err := cc.Query("ReadAsset", "asset1").AsBytes(context.Background()) 43 | if err != nil { 44 | log.Fatalf("connection.query: %v", err) 45 | } 46 | log.Print("Queried: ", string(res2)) 47 | } 48 | -------------------------------------------------------------------------------- /examples/cc_call/cfg.yaml: -------------------------------------------------------------------------------- 1 | discovery: 2 | type: gossip 3 | connection: 4 | host: peer0.org1.example.com:7051 5 | timeout: 5s 6 | 7 | tls_certs_map: 8 | - address: orderer.example.com:7050 9 | tls: 10 | enabled: true 11 | ca_cert_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt 12 | cert_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/signcerts/cert.pem 13 | key_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/keystore/ef18cb3e70e5fdf825e4a83f40243d64a8a3a824b9b0fd99cf363856f5c6c174_sk 14 | - address: peer0.org2.example.com:9051 15 | tls: 16 | enabled: true 17 | ca_cert_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/tlscacerts/tls-localhost-8054-ca-org2.pem 18 | cert_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/signcerts/cert.pem 19 | key_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/keystore/15ba9010b75e3869ae1ad69191d59a9951a692fbde4b9a07b8bf08fb0173b3df_sk 20 | - address: peer0.org1.example.com:7051 21 | tls: 22 | enabled: true 23 | ca_cert_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/tlscacerts/tls-localhost-7054-ca-org1.pem 24 | cert_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/signcerts/cert.pem 25 | key_path: /Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/keystore/76d679929878afc06711d3c611af1c84dcac5be7cd6563d8338a7500b79109d9_sk 26 | -------------------------------------------------------------------------------- /examples/channel_info/blockchanin_info.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/base64" 6 | "fmt" 7 | "log" 8 | 9 | "github.com/golang/protobuf/ptypes/empty" 10 | 11 | "github.com/s7techlab/hlf-sdk-go/block" 12 | "github.com/s7techlab/hlf-sdk-go/client" 13 | _ "github.com/s7techlab/hlf-sdk-go/crypto/ecdsa" 14 | "github.com/s7techlab/hlf-sdk-go/identity" 15 | "github.com/s7techlab/hlf-sdk-go/service/systemcc/cscc" 16 | "github.com/s7techlab/hlf-sdk-go/service/systemcc/qscc" 17 | ) 18 | 19 | func main() { 20 | 21 | mspId := "Org1MSP" 22 | configPath := "./cfg.yaml" 23 | 24 | signer, err := identity.NewSigningFromFile( 25 | mspId, 26 | // PROVIDE YOUR OWN PATHS 27 | "../../../../github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/cert.pem", 28 | "../../../../github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/02a48982a93c9a1fbf7e9702f82d14578aef9662362346ecfe8b3cde50da6799_sk", 29 | ) 30 | 31 | core, err := client.New(context.Background(), 32 | client.WithDefaultSigner(signer), client.WithConfigYaml(configPath)) 33 | if err != nil { 34 | log.Fatalln(`unable to initialize core:`, err) 35 | } 36 | 37 | ctx := context.Background() 38 | 39 | // get chainInfo for all joined channels 40 | chInfo, err := cscc.NewCSCC(core, block.FabricV2).GetChannels(ctx, &empty.Empty{}) 41 | if err != nil { 42 | log.Fatalln(`failed to fetch channel list:`, err) 43 | } 44 | for _, ch := range chInfo.Channels { 45 | fmt.Printf("Fetching info about channel: %s\n", ch.ChannelId) 46 | // get blockchain info about channel 47 | 48 | blockchainInfo, err := qscc.NewQSCC(core).GetChainInfo(ctx, &qscc.GetChainInfoRequest{ChannelName: ch.ChannelId}) 49 | if err != nil { 50 | fmt.Println(`Failed to fetch info about channel:`, err) 51 | continue 52 | } 53 | fmt.Printf("Block length: %d, last block: %s, prev block: %s\n", blockchainInfo.Height, base64.StdEncoding.EncodeToString(blockchainInfo.CurrentBlockHash), base64.StdEncoding.EncodeToString(blockchainInfo.PreviousBlockHash)) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/cli/README.md: -------------------------------------------------------------------------------- 1 | # Install and instantiate cli 2 | 3 | Tool for installing and instantiating chaincode 4 | 5 | Required flags: 6 | - mspId - identifier of MSP 7 | - mspPath - path to `msp` directory 8 | - configPath - path to SDK config ([example](../caclient/config.yaml)) 9 | - channel - channel name for instantiated chaincode 10 | - cc - chaincode name 11 | - ccPath - path to chaincode realtively `$GOPATH` 12 | - ccVersion - chaincode version 13 | - ccPolicy - instantiation policy 14 | - ccArgs - chaincode instantiation arguments 15 | - ccTransient - chaincode transient arguments 16 | -------------------------------------------------------------------------------- /examples/cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "flag" 7 | "log" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/api" 10 | _ "github.com/s7techlab/hlf-sdk-go/crypto/ecdsa" 11 | ) 12 | 13 | var ctx = context.Background() 14 | 15 | var ( 16 | mspId = flag.String(`mspId`, ``, `MspId`) 17 | mspPath = flag.String(`mspPath`, ``, `path to admin certificate`) 18 | configPath = flag.String(`configPath`, ``, `path to configuration file`) 19 | 20 | channel = flag.String(`channel`, ``, `channel name`) 21 | cc = flag.String(`cc`, ``, `chaincode name`) 22 | ccPath = flag.String(`ccPath`, ``, `chaincode path`) 23 | ccVersion = flag.String(`ccVersion`, ``, `chaincode version`) 24 | ccPolicy = flag.String(`ccPolicy`, ``, `chaincode endorsement policy`) 25 | ccArgs = flag.String(`ccArgs`, ``, `chaincode instantiation arguments`) 26 | ccTransient = flag.String(`ccTransient`, ``, `chaincode transient arguments`) 27 | ) 28 | 29 | func main() { 30 | // no instantiate option yet 31 | 32 | //id, err := identity.SignerFromMSPPath(*mspId, *mspPath) 33 | // 34 | //if err != nil { 35 | // log.Fatalln(`Failed to load identity:`, err) 36 | //} 37 | // 38 | //l, _ := zap.NewDevelopment() 39 | // 40 | //core, err := client.NewCore(id, client.WithConfigYaml(*configPath), client.WithLogger(l)) 41 | //if err != nil { 42 | // log.Fatalln(`unable to initialize core:`, err) 43 | //} 44 | 45 | //if err = core.Chaincode(*cc).Install(ctx, *ccPath, *ccVersion); err != nil { 46 | // log.Fatalln(err) 47 | //} 48 | // 49 | //if err = core.Chaincode(*cc).Instantiate( 50 | // ctx, 51 | // *channel, 52 | // *ccPath, 53 | // *ccVersion, 54 | // *ccPolicy, 55 | // util.ToChaincodeArgs(*ccArgs), 56 | // prepareTransArgs(*ccTransient), 57 | //); err != nil { 58 | // log.Fatalln(err) 59 | //} 60 | 61 | log.Println(`successfully initiated`) 62 | } 63 | 64 | func prepareTransArgs(args string) api.TransArgs { 65 | var t map[string]json.RawMessage 66 | var err error 67 | if err = json.Unmarshal([]byte(args), &t); err != nil { 68 | panic(err) 69 | } 70 | 71 | tt := api.TransArgs{} 72 | 73 | for k, v := range t { 74 | if tt[k], err = v.MarshalJSON(); err != nil { 75 | panic(err) 76 | } 77 | } 78 | return tt 79 | } 80 | 81 | func init() { 82 | flag.Parse() 83 | } 84 | -------------------------------------------------------------------------------- /examples/discovery_and_transaction/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/s7techlab/hlf-sdk-go/client" 8 | "github.com/s7techlab/hlf-sdk-go/identity" 9 | ) 10 | 11 | func main() { 12 | 13 | // TODO change paths to YOUR OWN 14 | signer, err := identity.NewSigningFromFile( 15 | "Org1MSP", 16 | "/Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/cert.pem", 17 | "/Users/bogatyr285/work/go/src/github.com/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/02a48982a93c9a1fbf7e9702f82d14578aef9662362346ecfe8b3cde50da6799_sk", 18 | ) 19 | 20 | core, err := client.New(context.Background(), 21 | client.WithDefaultSigner(signer), client.WithConfigYaml("./cfg.yaml")) 22 | if err != nil { 23 | log.Fatalf("create client core: %v", err) 24 | } 25 | conn, err := core.Channel("mychannel").Chaincode(context.Background(), "basic") 26 | if err != nil { 27 | log.Fatalf("connection.Channel: %v", err) 28 | } 29 | 30 | res, tx, err := conn.Invoke("UpdateAsset"). 31 | ArgString("asset1", "testCOLOR", "1337", "testOWNER", "228"). 32 | Do(context.Background()) 33 | if err != nil { 34 | log.Fatalf("connection.invoke: %v", err) 35 | } 36 | 37 | log.Print("Invoked", tx, res) 38 | } 39 | -------------------------------------------------------------------------------- /examples/event-listener/README.md: -------------------------------------------------------------------------------- 1 | ### Event Listener 2 | 3 | #### Required environment variables 4 | - **MSP_ID** - MSP identifier 5 | - **CONFIG_PATH** - path to configuration file of SDK _(eg. config.yaml)_ 6 | - **CERT_PATH** - path to certificate file of identity _(eg. signcerts/cert.pem)_ 7 | - **KEY_PATH** - path to private key of identity _(eg. keystore/your_pk)_ 8 | - **CHANNEL** - channel used for listening new events 9 | - **CHAINCODE** - chaincode used for used listening chaincode events 10 | 11 | #### Usage 12 | Run with environment variables described above: 13 | ```bash 14 | go run main.go 15 | ``` -------------------------------------------------------------------------------- /examples/event-listener/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "log" 8 | "os" 9 | "sync" 10 | "time" 11 | 12 | "go.uber.org/zap" 13 | 14 | "github.com/s7techlab/hlf-sdk-go/client" 15 | _ "github.com/s7techlab/hlf-sdk-go/crypto/ecdsa" 16 | "github.com/s7techlab/hlf-sdk-go/identity" 17 | ) 18 | 19 | func main() { 20 | mspId := os.Getenv(`MSP_ID`) 21 | if mspId == `` { 22 | log.Fatalln(`MSP_ID env must be defined`) 23 | } 24 | 25 | configPath := os.Getenv(`CONFIG_PATH`) 26 | if configPath == `` { 27 | log.Fatalln(`CONFIG_PATH env must be defined`) 28 | } 29 | 30 | mspPath := os.Getenv(`MSP_PATH`) 31 | if mspPath == `` { 32 | log.Fatalln(`MSP_PATH env must be defined`) 33 | } 34 | 35 | channel := os.Getenv(`CHANNEL`) 36 | if channel == `` { 37 | log.Fatalln(`CHANNEL env must be defined`) 38 | } 39 | 40 | chaincode := os.Getenv(`CHAINCODE`) 41 | if chaincode == `` { 42 | log.Fatalln(`CHAINCODE env must be defined`) 43 | } 44 | 45 | signer, err := identity.NewSigningFromMSPPath(mspId, mspPath) 46 | 47 | if err != nil { 48 | log.Fatalln(`Failed to load identity:`, err) 49 | } 50 | 51 | l, _ := zap.NewProduction() 52 | 53 | core, err := client.New(context.Background(), 54 | client.WithDefaultSigner(signer), client.WithConfigYaml(configPath), client.WithLogger(l)) 55 | if err != nil { 56 | log.Fatalln(`unable to initialize core:`, err) 57 | } 58 | 59 | cc, err := core.Channel(channel).Chaincode(context.Background(), chaincode) 60 | if err != nil { 61 | log.Fatalln(`unable to initialize channel:`, err) 62 | } 63 | 64 | var wg sync.WaitGroup 65 | 66 | for i := 0; i < 10; i++ { 67 | wg.Add(1) 68 | 69 | go func(idx int, wg *sync.WaitGroup) { 70 | defer wg.Done() 71 | sub, err := cc.Subscribe(context.Background()) 72 | if err != nil { 73 | log.Printf("Failed to process rouitine %d: %s", idx, err) 74 | return 75 | } 76 | defer func() { _ = sub.Close() }() 77 | 78 | for { 79 | select { 80 | case ev := <-sub.Events(): 81 | b, _ := json.MarshalIndent(ev, ` `, "\t") 82 | fmt.Printf("Routine %d, received event:\n %v\n", idx, string(b)) 83 | case err := <-sub.Errors(): 84 | log.Println(`error occurred:`, err) 85 | return 86 | case <-time.After(time.Duration(idx) * time.Second): 87 | fmt.Printf("Routine %d is closing\n", idx) 88 | return 89 | } 90 | } 91 | 92 | }(i, &wg) 93 | } 94 | 95 | wg.Wait() 96 | 97 | } 98 | -------------------------------------------------------------------------------- /examples/example_cc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/hyperledger/fabric-chaincode-go/shim" 7 | "github.com/hyperledger/fabric-protos-go/peer" 8 | ) 9 | 10 | func main() { 11 | if err := shim.Start(&exampleCc{}); err != nil { 12 | log.Fatal(err) 13 | } 14 | } 15 | 16 | type exampleCc struct { 17 | } 18 | 19 | func (*exampleCc) Init(stub shim.ChaincodeStubInterface) peer.Response { 20 | t, err := stub.GetTransient() 21 | if err != nil { 22 | return shim.Error(err.Error()) 23 | } 24 | 25 | log.Println(t) 26 | 27 | if err = stub.PutState(`key`, t[`key`]); err != nil { 28 | return shim.Error(err.Error()) 29 | } 30 | 31 | return shim.Success(nil) 32 | } 33 | 34 | func (*exampleCc) Invoke(stub shim.ChaincodeStubInterface) peer.Response { 35 | t, err := stub.GetTransient() 36 | if err != nil { 37 | return shim.Error(err.Error()) 38 | } 39 | 40 | log.Println(t) 41 | 42 | if err = stub.PutState(`key`, t[`key`]); err != nil { 43 | return shim.Error(err.Error()) 44 | } 45 | 46 | return shim.Success(nil) 47 | } 48 | -------------------------------------------------------------------------------- /identity/msp_opts.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | func WithSkipConfig() MSPOpt { 4 | return func(mspOpts *MSPOpts) { 5 | mspOpts.skipConfig = true 6 | } 7 | } 8 | 9 | func WithAdminMSPPath(adminMSPPath string) MSPOpt { 10 | return func(mspOpts *MSPOpts) { 11 | mspOpts.adminMSPPath = adminMSPPath 12 | } 13 | } 14 | 15 | func WithSignCertPath(signCertPath string) MSPOpt { 16 | return func(mspOpts *MSPOpts) { 17 | mspOpts.signCertPath = signCertPath 18 | } 19 | } 20 | 21 | func WithSignKeyPath(signKeyPath string) MSPOpt { 22 | return func(mspOpts *MSPOpts) { 23 | mspOpts.signKeyPath = signKeyPath 24 | } 25 | } 26 | 27 | func WithSignCert(signCert []byte) MSPOpt { 28 | return func(mspOpts *MSPOpts) { 29 | mspOpts.signCert = signCert 30 | } 31 | } 32 | 33 | func WithSignKey(signKey []byte) MSPOpt { 34 | return func(mspOpts *MSPOpts) { 35 | mspOpts.signKey = signKey 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPAdmin/cacerts/localhost-7054-ca-org1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICJzCCAc2gAwIBAgIUJTrIJIgwwEklgs//ULGuM+74+JowCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMzcwMzI2MTU1MDAw 6 | WjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV 7 | BAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT 8 | Y2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAeq 9 | eyQwfHQqLRoVFAc9xjFB06qJ8+Jk2SUo5kWqfPQ7Bq0t+ECcIdscJlpIquizlYK8 10 | uiDRfRjZ9zfE/2kceQ+jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG 11 | AQH/AgEBMB0GA1UdDgQWBBTELLG1wZxB+QZmEWlva9Qe6OUmDjAKBggqhkjOPQQD 12 | AgNIADBFAiEAljA5hOICu3K8LOyrCbhFpOBqvlwIO9fFZ0ljcHbb9DsCIH0i8Erd 13 | I5oe0S9AS4GEjwnGSetdfbPWxBZEZsjdbGCS 14 | -----END CERTIFICATE----- 15 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPAdmin/config.yaml: -------------------------------------------------------------------------------- 1 | NodeOUs: 2 | Enable: true 3 | ClientOUIdentifier: 4 | Certificate: cacerts/localhost-7054-ca-org1.pem 5 | OrganizationalUnitIdentifier: client 6 | PeerOUIdentifier: 7 | Certificate: cacerts/localhost-7054-ca-org1.pem 8 | OrganizationalUnitIdentifier: peer 9 | AdminOUIdentifier: 10 | Certificate: cacerts/localhost-7054-ca-org1.pem 11 | OrganizationalUnitIdentifier: admin 12 | OrdererOUIdentifier: 13 | Certificate: cacerts/localhost-7054-ca-org1.pem 14 | OrganizationalUnitIdentifier: orderer 15 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPAdmin/keystore/4895cac2d326f796ca79f8ca7c9051c8417373012d2b5f62fb01dd9f0566fc72_sk: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjN6AS8GtB4rkxx2b 3 | 6LClbqPVlfWhcizBoNQQLOhbvXehRANCAATZTScxpEmnRp1COW7yO6Oi49PP6fcA 4 | TyguxsnSd012+4H0GnyOcv5/0a8AX+Xw3yatsISew9PMmH131H07uK2z 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPAdmin/signcerts/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICsDCCAlegAwIBAgIUIzfjMyArX1kPAJ6NjDYMDsyEex4wCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMjMwMzMwMTU1NTAw 6 | WjBgMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV 7 | BAoTC0h5cGVybGVkZ2VyMQ4wDAYDVQQLEwVhZG1pbjESMBAGA1UEAxMJb3JnMWFk 8 | bWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2U0nMaRJp0adQjlu8jujouPT 9 | z+n3AE8oLsbJ0ndNdvuB9Bp8jnL+f9GvAF/l8N8mrbCEnsPTzJh9d9R9O7its6OB 10 | 3jCB2zAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUswGr 11 | N+gWHr2M/Rgo7PjwVn52H4AwHwYDVR0jBBgwFoAUxCyxtcGcQfkGZhFpb2vUHujl 12 | Jg4wHgYDVR0RBBcwFYITdml0aWtvLW1hYy5ncm91cC5zNzBbBggqAwQFBgcIAQRP 13 | eyJhdHRycyI6eyJoZi5BZmZpbGlhdGlvbiI6IiIsImhmLkVucm9sbG1lbnRJRCI6 14 | Im9yZzFhZG1pbiIsImhmLlR5cGUiOiJhZG1pbiJ9fTAKBggqhkjOPQQDAgNHADBE 15 | AiBid03TGjVvBaIe+5tpE9PvrTDfDA9VCn96Z3hmvTVipAIgE9PtxRF6UIG9I7h/ 16 | +zOt4w927dn+5vRIKCbiJXdi+7c= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPAdmin/testdata.go: -------------------------------------------------------------------------------- 1 | package Org1MSPAdmin 2 | 3 | import _ "embed" 4 | 5 | var ( 6 | //go:embed cacerts/localhost-7054-ca-org1.pem 7 | CACert []byte 8 | 9 | //go:embed signcerts/cert.pem 10 | SignCert []byte 11 | ) 12 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeer/cacerts/localhost-7054-ca-org1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICJzCCAc2gAwIBAgIUJTrIJIgwwEklgs//ULGuM+74+JowCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMzcwMzI2MTU1MDAw 6 | WjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV 7 | BAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT 8 | Y2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAeq 9 | eyQwfHQqLRoVFAc9xjFB06qJ8+Jk2SUo5kWqfPQ7Bq0t+ECcIdscJlpIquizlYK8 10 | uiDRfRjZ9zfE/2kceQ+jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG 11 | AQH/AgEBMB0GA1UdDgQWBBTELLG1wZxB+QZmEWlva9Qe6OUmDjAKBggqhkjOPQQD 12 | AgNIADBFAiEAljA5hOICu3K8LOyrCbhFpOBqvlwIO9fFZ0ljcHbb9DsCIH0i8Erd 13 | I5oe0S9AS4GEjwnGSetdfbPWxBZEZsjdbGCS 14 | -----END CERTIFICATE----- 15 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeer/config.yaml: -------------------------------------------------------------------------------- 1 | NodeOUs: 2 | Enable: true 3 | ClientOUIdentifier: 4 | Certificate: cacerts/localhost-7054-ca-org1.pem 5 | OrganizationalUnitIdentifier: client 6 | PeerOUIdentifier: 7 | Certificate: cacerts/localhost-7054-ca-org1.pem 8 | OrganizationalUnitIdentifier: peer 9 | AdminOUIdentifier: 10 | Certificate: cacerts/localhost-7054-ca-org1.pem 11 | OrganizationalUnitIdentifier: admin 12 | OrdererOUIdentifier: 13 | Certificate: cacerts/localhost-7054-ca-org1.pem 14 | OrganizationalUnitIdentifier: orderer 15 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeer/keystore/d9e8fe76f63667c8fdaf1bbbd222111a93c4decc866899848239b011896bee59_sk: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg99ramoahWACdqrSH 3 | kG0FnVt7PfbEt+Hx5gaOyfphyqihRANCAASHU3KTTC8NPAD2Nr75dWyhtBdhLdDw 4 | dOXjrdTDgvJaOakeykDi5R8Ar7LnJbQJE3zTk42grWxurI3i4v+vf70v 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeer/signcerts/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqTCCAlCgAwIBAgIUbJGsh8g7lzXsKRffK+DIAKSK1f8wCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMjMwMzMwMTU1NTAw 6 | WjBbMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV 7 | BAoTC0h5cGVybGVkZ2VyMQ0wCwYDVQQLEwRwZWVyMQ4wDAYDVQQDEwVwZWVyMDBZ 8 | MBMGByqGSM49AgEGCCqGSM49AwEHA0IABIdTcpNMLw08APY2vvl1bKG0F2Et0PB0 9 | 5eOt1MOC8lo5qR7KQOLlHwCvsucltAkTfNOTjaCtbG6sjeLi/69/vS+jgdwwgdkw 10 | DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFDmCrhlTaYf 11 | x6UeZoq1SFMwdkBvMB8GA1UdIwQYMBaAFMQssbXBnEH5BmYRaW9r1B7o5SYOMCEG 12 | A1UdEQQaMBiCFnBlZXIwLm9yZzEuZXhhbXBsZS5jb20wVgYIKgMEBQYHCAEESnsi 13 | YXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJw 14 | ZWVyMCIsImhmLlR5cGUiOiJwZWVyIn19MAoGCCqGSM49BAMCA0cAMEQCIHvzwHnN 15 | s4F9Hq5Jt+y4Jh6LFF8MGkArznzdi1aX0gBZAiA7Dj3miR7C5rvRH73qBZRQZAWz 16 | QEgo2dctu1L8DiSfQQ== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeer/testdata.go: -------------------------------------------------------------------------------- 1 | package Org1MSPPeer 2 | 3 | import ( 4 | _ "embed" 5 | 6 | mspproto "github.com/hyperledger/fabric-protos-go/msp" 7 | ) 8 | 9 | var ( 10 | ID = `Org1MSP` 11 | 12 | ////go:embed admincerts/cert.pem 13 | //AdminCert []byte 14 | 15 | //go:embed cacerts/localhost-7054-ca-org1.pem 16 | CACert []byte 17 | 18 | //go:embed signcerts/cert.pem 19 | SignCert []byte 20 | 21 | //go:embed config.yaml 22 | ConfigYaml []byte 23 | ) 24 | 25 | func FabricMSPConfig() *mspproto.FabricMSPConfig { 26 | return &mspproto.FabricMSPConfig{ 27 | Name: ID, 28 | RootCerts: [][]byte{CACert}, 29 | IntermediateCerts: [][]byte{}, 30 | //Admins: [][]byte{AdminCert}, 31 | RevocationList: nil, 32 | SigningIdentity: nil, 33 | OrganizationalUnitIdentifiers: nil, 34 | CryptoConfig: nil, 35 | TlsRootCerts: nil, 36 | TlsIntermediateCerts: nil, 37 | // same as config yaml 38 | FabricNodeOus: &mspproto.FabricNodeOUs{ 39 | Enable: true, 40 | ClientOuIdentifier: &mspproto.FabricOUIdentifier{ 41 | Certificate: CACert, 42 | OrganizationalUnitIdentifier: "client", 43 | }, 44 | PeerOuIdentifier: &mspproto.FabricOUIdentifier{ 45 | Certificate: CACert, 46 | OrganizationalUnitIdentifier: "peer", 47 | }, 48 | AdminOuIdentifier: &mspproto.FabricOUIdentifier{ 49 | Certificate: CACert, 50 | OrganizationalUnitIdentifier: "admin", 51 | }, 52 | OrdererOuIdentifier: &mspproto.FabricOUIdentifier{ 53 | Certificate: CACert, 54 | OrganizationalUnitIdentifier: "orderer", 55 | }, 56 | }, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeerAndAdmin/admincerts/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICsDCCAlegAwIBAgIUIzfjMyArX1kPAJ6NjDYMDsyEex4wCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMjMwMzMwMTU1NTAw 6 | WjBgMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV 7 | BAoTC0h5cGVybGVkZ2VyMQ4wDAYDVQQLEwVhZG1pbjESMBAGA1UEAxMJb3JnMWFk 8 | bWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2U0nMaRJp0adQjlu8jujouPT 9 | z+n3AE8oLsbJ0ndNdvuB9Bp8jnL+f9GvAF/l8N8mrbCEnsPTzJh9d9R9O7its6OB 10 | 3jCB2zAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUswGr 11 | N+gWHr2M/Rgo7PjwVn52H4AwHwYDVR0jBBgwFoAUxCyxtcGcQfkGZhFpb2vUHujl 12 | Jg4wHgYDVR0RBBcwFYITdml0aWtvLW1hYy5ncm91cC5zNzBbBggqAwQFBgcIAQRP 13 | eyJhdHRycyI6eyJoZi5BZmZpbGlhdGlvbiI6IiIsImhmLkVucm9sbG1lbnRJRCI6 14 | Im9yZzFhZG1pbiIsImhmLlR5cGUiOiJhZG1pbiJ9fTAKBggqhkjOPQQDAgNHADBE 15 | AiBid03TGjVvBaIe+5tpE9PvrTDfDA9VCn96Z3hmvTVipAIgE9PtxRF6UIG9I7h/ 16 | +zOt4w927dn+5vRIKCbiJXdi+7c= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeerAndAdmin/cacerts/localhost-7054-ca-org1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICJzCCAc2gAwIBAgIUJTrIJIgwwEklgs//ULGuM+74+JowCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMzcwMzI2MTU1MDAw 6 | WjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV 7 | BAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT 8 | Y2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAeq 9 | eyQwfHQqLRoVFAc9xjFB06qJ8+Jk2SUo5kWqfPQ7Bq0t+ECcIdscJlpIquizlYK8 10 | uiDRfRjZ9zfE/2kceQ+jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG 11 | AQH/AgEBMB0GA1UdDgQWBBTELLG1wZxB+QZmEWlva9Qe6OUmDjAKBggqhkjOPQQD 12 | AgNIADBFAiEAljA5hOICu3K8LOyrCbhFpOBqvlwIO9fFZ0ljcHbb9DsCIH0i8Erd 13 | I5oe0S9AS4GEjwnGSetdfbPWxBZEZsjdbGCS 14 | -----END CERTIFICATE----- 15 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeerAndAdmin/config.yaml: -------------------------------------------------------------------------------- 1 | NodeOUs: 2 | Enable: true 3 | ClientOUIdentifier: 4 | Certificate: cacerts/localhost-7054-ca-org1.pem 5 | OrganizationalUnitIdentifier: client 6 | PeerOUIdentifier: 7 | Certificate: cacerts/localhost-7054-ca-org1.pem 8 | OrganizationalUnitIdentifier: peer 9 | AdminOUIdentifier: 10 | Certificate: cacerts/localhost-7054-ca-org1.pem 11 | OrganizationalUnitIdentifier: admin 12 | OrdererOUIdentifier: 13 | Certificate: cacerts/localhost-7054-ca-org1.pem 14 | OrganizationalUnitIdentifier: orderer 15 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeerAndAdmin/keystore/4895cac2d326f796ca79f8ca7c9051c8417373012d2b5f62fb01dd9f0566fc72_sk: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjN6AS8GtB4rkxx2b 3 | 6LClbqPVlfWhcizBoNQQLOhbvXehRANCAATZTScxpEmnRp1COW7yO6Oi49PP6fcA 4 | TyguxsnSd012+4H0GnyOcv5/0a8AX+Xw3yatsISew9PMmH131H07uK2z 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeerAndAdmin/keystore/d9e8fe76f63667c8fdaf1bbbd222111a93c4decc866899848239b011896bee59_sk: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg99ramoahWACdqrSH 3 | kG0FnVt7PfbEt+Hx5gaOyfphyqihRANCAASHU3KTTC8NPAD2Nr75dWyhtBdhLdDw 4 | dOXjrdTDgvJaOakeykDi5R8Ar7LnJbQJE3zTk42grWxurI3i4v+vf70v 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /identity/testdata/Org1MSPPeerAndAdmin/signcerts/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqTCCAlCgAwIBAgIUbJGsh8g7lzXsKRffK+DIAKSK1f8wCgYIKoZIzj0EAwIw 3 | cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH 4 | EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 5 | Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwMzMwMTU1MDAwWhcNMjMwMzMwMTU1NTAw 6 | WjBbMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV 7 | BAoTC0h5cGVybGVkZ2VyMQ0wCwYDVQQLEwRwZWVyMQ4wDAYDVQQDEwVwZWVyMDBZ 8 | MBMGByqGSM49AgEGCCqGSM49AwEHA0IABIdTcpNMLw08APY2vvl1bKG0F2Et0PB0 9 | 5eOt1MOC8lo5qR7KQOLlHwCvsucltAkTfNOTjaCtbG6sjeLi/69/vS+jgdwwgdkw 10 | DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFDmCrhlTaYf 11 | x6UeZoq1SFMwdkBvMB8GA1UdIwQYMBaAFMQssbXBnEH5BmYRaW9r1B7o5SYOMCEG 12 | A1UdEQQaMBiCFnBlZXIwLm9yZzEuZXhhbXBsZS5jb20wVgYIKgMEBQYHCAEESnsi 13 | YXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJw 14 | ZWVyMCIsImhmLlR5cGUiOiJwZWVyIn19MAoGCCqGSM49BAMCA0cAMEQCIHvzwHnN 15 | s4F9Hq5Jt+y4Jh6LFF8MGkArznzdi1aX0gBZAiA7Dj3miR7C5rvRH73qBZRQZAWz 16 | QEgo2dctu1L8DiSfQQ== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /observer/README.md: -------------------------------------------------------------------------------- 1 | # Observer: Observing blocks and events for particular channel or peer 2 | 3 | Main features: 4 | 5 | * Stream of channel blocks from peer 6 | * Stream of all channels blocks from peer 7 | * Auto reconnection when block or event stream interrupted 8 | 9 | Every feature can be used for common block, also for parsed block from [block](../block/block.proto) 10 | -------------------------------------------------------------------------------- /observer/block.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | type Block[T any] struct { 4 | Channel string 5 | Block T 6 | } 7 | -------------------------------------------------------------------------------- /observer/channel_blocks_common.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "github.com/hyperledger/fabric-protos-go/common" 5 | 6 | "github.com/s7techlab/hlf-sdk-go/api" 7 | ) 8 | 9 | type ( 10 | ChannelBlocksCommon struct { 11 | *ChannelBlocks[*common.Block] 12 | } 13 | ) 14 | 15 | func NewChannelBlocksCommon(channel string, blocksDeliver api.BlocksDeliverer, seekFromFetcher SeekFromFetcher, opts ...ChannelBlocksOpt) *ChannelBlocksCommon { 16 | createStreamWithRetry := CreateBlockStreamWithRetryDelay[*common.Block](DefaultConnectRetryDelay) 17 | 18 | chBlocks := NewChannelBlocks[*common.Block](channel, blocksDeliver.Blocks, createStreamWithRetry, seekFromFetcher, opts...) 19 | 20 | return &ChannelBlocksCommon{ChannelBlocks: chBlocks} 21 | } 22 | -------------------------------------------------------------------------------- /observer/channel_blocks_parsed.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "github.com/s7techlab/hlf-sdk-go/api" 5 | hlfproto "github.com/s7techlab/hlf-sdk-go/block" 6 | ) 7 | 8 | type ( 9 | ChannelBlocksParsed struct { 10 | *ChannelBlocks[*hlfproto.Block] 11 | } 12 | ) 13 | 14 | func NewChannelBlocksParsed(channel string, blocksDeliver api.ParsedBlocksDeliverer, seekFromFetcher SeekFromFetcher, opts ...ChannelBlocksOpt) *ChannelBlocksParsed { 15 | createStreamWithRetry := CreateBlockStreamWithRetryDelay[*hlfproto.Block](DefaultConnectRetryDelay) 16 | 17 | chBlocks := NewChannelBlocks[*hlfproto.Block](channel, blocksDeliver.ParsedBlocks, createStreamWithRetry, seekFromFetcher, opts...) 18 | 19 | return &ChannelBlocksParsed{ChannelBlocks: chBlocks} 20 | } 21 | -------------------------------------------------------------------------------- /observer/channel_blocks_stream.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | type ( 9 | CreateBlockStream[T any] func(context.Context) (<-chan T, error) 10 | 11 | CreateBlockStreamWithRetry[T any] func(context.Context, CreateBlockStream[T]) (<-chan T, error) 12 | ) 13 | 14 | func CreateBlockStreamWithRetryDelay[T any](delay time.Duration) CreateBlockStreamWithRetry[T] { 15 | return func(ctx context.Context, createBlockStream CreateBlockStream[T]) (<-chan T, error) { 16 | for { 17 | select { 18 | case <-ctx.Done(): 19 | return nil, nil 20 | default: 21 | } 22 | 23 | blocks, err := createBlockStream(ctx) 24 | if err == nil { 25 | return blocks, nil 26 | } 27 | 28 | time.Sleep(delay) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /observer/channels_blocks_peer_common.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "github.com/hyperledger/fabric-protos-go/common" 5 | 6 | "github.com/s7techlab/hlf-sdk-go/api" 7 | ) 8 | 9 | type ChannelsBlocksPeerCommon struct { 10 | *ChannelsBlocksPeer[*common.Block] 11 | } 12 | 13 | func NewChannelsBlocksPeerCommon(peerChannels PeerChannelsGetter, blocksDeliver api.BlocksDeliverer, opts ...ChannelsBlocksPeerOpt) *ChannelsBlocksPeerCommon { 14 | createStreamWithRetry := CreateBlockStreamWithRetryDelay[*common.Block](DefaultConnectRetryDelay) 15 | 16 | channelsBlocksPeerCommon := NewChannelsBlocksPeer[*common.Block](peerChannels, blocksDeliver.Blocks, createStreamWithRetry, opts...) 17 | 18 | return &ChannelsBlocksPeerCommon{ChannelsBlocksPeer: channelsBlocksPeerCommon} 19 | } 20 | -------------------------------------------------------------------------------- /observer/channels_blocks_peer_concurrently.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "go.uber.org/zap" 8 | ) 9 | 10 | type ChannelBlocksWithName[T any] struct { 11 | Name string 12 | Blocks <-chan *Block[T] 13 | } 14 | 15 | type ChannelWithChannels[T any] struct { 16 | channels chan *ChannelBlocksWithName[T] 17 | } 18 | 19 | func (cwc *ChannelWithChannels[T]) Observe() <-chan *ChannelBlocksWithName[T] { 20 | return cwc.channels 21 | } 22 | 23 | func (acb *ChannelsBlocksPeer[T]) ObserveByChannels(ctx context.Context) *ChannelWithChannels[T] { 24 | channelWithChannels := &ChannelWithChannels[T]{ 25 | channels: make(chan *ChannelBlocksWithName[T]), 26 | } 27 | 28 | // ctxObserve using for nested control process without stopped primary context 29 | ctxObserve, cancel := context.WithCancel(ctx) 30 | acb.cancelObserve = cancel 31 | 32 | acb.startNotObservedChannelsConcurrently(ctxObserve, acb.initChannelsObservers(), channelWithChannels) 33 | 34 | // init new channels if they are fetched 35 | go func() { 36 | ticker := time.NewTicker(acb.refreshPeriod) 37 | defer func() { 38 | ticker.Stop() 39 | close(channelWithChannels.channels) 40 | }() 41 | 42 | for { 43 | select { 44 | case <-ctx.Done(): 45 | return 46 | 47 | case <-ticker.C: 48 | acb.startNotObservedChannelsConcurrently(ctxObserve, acb.initChannelsObservers(), channelWithChannels) 49 | } 50 | } 51 | }() 52 | 53 | // closer 54 | go func() { 55 | <-ctx.Done() 56 | acb.Stop() 57 | }() 58 | 59 | return channelWithChannels 60 | } 61 | 62 | func (acb *ChannelsBlocksPeer[T]) startNotObservedChannelsConcurrently( 63 | ctx context.Context, 64 | notObservedChannels []*ChannelBlocks[T], 65 | channelWithChannels *ChannelWithChannels[T], 66 | ) { 67 | 68 | for _, notObservedChannel := range notObservedChannels { 69 | chBlocks := notObservedChannel 70 | 71 | if _, err := chBlocks.Observe(ctx); err != nil { 72 | acb.logger.Warn(`init channel observer concurrently`, zap.String("channel", notObservedChannel.channel), zap.Error(err)) 73 | } 74 | 75 | go func() { 76 | channelWithChannels.channels <- &ChannelBlocksWithName[T]{Name: chBlocks.channel, Blocks: chBlocks.channelWithBlocks} 77 | }() 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /observer/channels_blocks_peer_parsed.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "github.com/s7techlab/hlf-sdk-go/api" 5 | hlfproto "github.com/s7techlab/hlf-sdk-go/block" 6 | ) 7 | 8 | type ChannelsBlocksPeerParsed struct { 9 | *ChannelsBlocksPeer[*hlfproto.Block] 10 | } 11 | 12 | func NewChannelsBlocksPeerParsed(peerChannels PeerChannelsGetter, blocksDeliver api.ParsedBlocksDeliverer, opts ...ChannelsBlocksPeerOpt) *ChannelsBlocksPeerParsed { 13 | createStreamWithRetry := CreateBlockStreamWithRetryDelay[*hlfproto.Block](DefaultConnectRetryDelay) 14 | 15 | channelsBlocksPeerParsed := NewChannelsBlocksPeer[*hlfproto.Block](peerChannels, blocksDeliver.ParsedBlocks, createStreamWithRetry, opts...) 16 | 17 | return &ChannelsBlocksPeerParsed{ChannelsBlocksPeer: channelsBlocksPeerParsed} 18 | } 19 | -------------------------------------------------------------------------------- /observer/old_files/event.go: -------------------------------------------------------------------------------- 1 | package old_files 2 | 3 | //import ( 4 | // "context" 5 | // 6 | // "github.com/hyperledger/fabric-protos-go/peer" 7 | //) 8 | // 9 | //type ( 10 | // Event struct { 11 | // Block *peer.ChaincodeEvent 12 | // Channel string 13 | // Error error 14 | // } 15 | // 16 | // CreateEventStream func(context.Context) (<-chan *peer.ChaincodeEvent, error) 17 | // 18 | // CreateEventStreamWithRetry func(context.Context, CreateEventStream) (<-chan *peer.ChaincodeEvent, error) 19 | // 20 | // EventTransformer interface { 21 | // Transform(*Event) 22 | // } 23 | //) 24 | -------------------------------------------------------------------------------- /observer/old_files/event_channel.go: -------------------------------------------------------------------------------- 1 | package old_files 2 | 3 | // type ( 4 | // EventChannel struct { 5 | // *Channel 6 | // eventsDeliverer api.EventsDeliverer 7 | // createEventStream CreateEventStream 8 | // createBlockStreamWithRetry CreateBlockStreamWithRetry 9 | // transformers []EventTransformer 10 | // 11 | // events chan *Event 12 | // } 13 | //) 14 | -------------------------------------------------------------------------------- /observer/old_files/event_peer.go: -------------------------------------------------------------------------------- 1 | package old_files 2 | 3 | // type ( 4 | // EventPeer struct { 5 | // peerChannels PeerChannels 6 | // eventObservers map[string]EventChannel 7 | // } 8 | //) 9 | -------------------------------------------------------------------------------- /observer/peer_channels_fetcher_mock.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hyperledger/fabric-protos-go/common" 8 | "github.com/hyperledger/fabric-protos-go/peer" 9 | ) 10 | 11 | type PeerChannelsFetcherMock struct { 12 | channels map[string]uint64 13 | } 14 | 15 | func NewPeerChannelsFetcherMock(channels map[string]uint64) *PeerChannelsFetcherMock { 16 | return &PeerChannelsFetcherMock{channels: channels} 17 | } 18 | 19 | func (p *PeerChannelsFetcherMock) URI() string { 20 | return "mock" 21 | } 22 | 23 | func (p *PeerChannelsFetcherMock) GetChannels(context.Context) (*peer.ChannelQueryResponse, error) { 24 | var channels []*peer.ChannelInfo 25 | for channelName := range p.channels { 26 | channels = append(channels, &peer.ChannelInfo{ChannelId: channelName}) 27 | } 28 | 29 | return &peer.ChannelQueryResponse{Channels: channels}, nil 30 | } 31 | 32 | func (p *PeerChannelsFetcherMock) GetChainInfo(_ context.Context, channel string) (*common.BlockchainInfo, error) { 33 | chHeight, exists := p.channels[channel] 34 | if !exists { 35 | return nil, fmt.Errorf("channel '%s' does not exist", channel) 36 | } 37 | 38 | return &common.BlockchainInfo{Height: chHeight}, nil 39 | } 40 | -------------------------------------------------------------------------------- /observer/peer_channels_mock.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type PeerChannelsMock struct { 8 | mu sync.Mutex 9 | channelsInfo map[string]*ChannelInfo 10 | } 11 | 12 | func NewPeerChannelsMock(channelsInfo ...*ChannelInfo) *PeerChannelsMock { 13 | channels := make(map[string]*ChannelInfo, len(channelsInfo)) 14 | for _, channelInfo := range channelsInfo { 15 | channels[channelInfo.Channel] = channelInfo 16 | } 17 | 18 | return &PeerChannelsMock{channelsInfo: channels} 19 | } 20 | 21 | func (p *PeerChannelsMock) URI() string { 22 | return "mock" 23 | } 24 | 25 | func (p *PeerChannelsMock) Channels() map[string]*ChannelInfo { 26 | p.mu.Lock() 27 | defer p.mu.Unlock() 28 | 29 | var copyChannelInfo = make(map[string]*ChannelInfo, len(p.channelsInfo)) 30 | for key, value := range p.channelsInfo { 31 | copyChannelInfo[key] = value 32 | } 33 | 34 | return copyChannelInfo 35 | } 36 | 37 | func (p *PeerChannelsMock) UpdateChannelInfo(channelInfo *ChannelInfo) { 38 | p.mu.Lock() 39 | defer p.mu.Unlock() 40 | 41 | p.channelsInfo[channelInfo.Channel] = channelInfo 42 | } 43 | -------------------------------------------------------------------------------- /observer/peer_channels_test.go: -------------------------------------------------------------------------------- 1 | package observer_test 2 | 3 | import ( 4 | "time" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/observer" 10 | testdata "github.com/s7techlab/hlf-sdk-go/testdata/blocks" 11 | ) 12 | 13 | var _ = Describe("Peer channels", func() { 14 | var ( 15 | peerChannelsFetcherMock observer.PeerChannelsFetcher 16 | ) 17 | BeforeEach(func() { 18 | peerChannelsFetcherMock = observer.NewPeerChannelsFetcherMock(testdata.ChannelsHeights) 19 | }) 20 | 21 | It("default peer channels, no channel matcher", func() { 22 | peerChannels, err := observer.NewPeerChannels(peerChannelsFetcherMock) 23 | Expect(err).To(BeNil()) 24 | 25 | peerChannels.Observe(ctx) 26 | time.Sleep(time.Millisecond * 100) 27 | 28 | channelsMap := peerChannels.Channels() 29 | 30 | sampleChannelInfo, exist := channelsMap[testdata.SampleChannel] 31 | Expect(exist).To(BeTrue()) 32 | Expect(sampleChannelInfo.Channel).To(Equal(testdata.SampleChannel)) 33 | Expect(sampleChannelInfo.Height).To(Equal(testdata.SampleChannelHeight)) 34 | 35 | fabcarChannelInfo, exist := channelsMap[testdata.FabcarChannel] 36 | Expect(exist).To(BeTrue()) 37 | Expect(fabcarChannelInfo.Channel).To(Equal(testdata.FabcarChannel)) 38 | Expect(fabcarChannelInfo.Height).To(Equal(testdata.FabcarChannelHeight)) 39 | }) 40 | 41 | It("default peer channels, with channel matcher, exclude Fabcar", func() { 42 | peerChannels, err := observer.NewPeerChannels(peerChannelsFetcherMock, 43 | observer.WithChannels([]observer.ChannelToMatch{{MatchPattern: testdata.SampleChannel}})) 44 | Expect(err).To(BeNil()) 45 | 46 | peerChannels.Observe(ctx) 47 | time.Sleep(time.Millisecond * 100) 48 | 49 | channelsMap := peerChannels.Channels() 50 | 51 | sampleChannelInfo, exist := channelsMap[testdata.SampleChannel] 52 | Expect(exist).To(BeTrue()) 53 | Expect(sampleChannelInfo.Channel).To(Equal(testdata.SampleChannel)) 54 | Expect(sampleChannelInfo.Height).To(Equal(testdata.SampleChannelHeight)) 55 | 56 | fabcarChannelInfo, exist := channelsMap[testdata.FabcarChannel] 57 | Expect(exist).To(BeFalse()) 58 | Expect(fabcarChannelInfo).To(BeNil()) 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /observer/stream.go: -------------------------------------------------------------------------------- 1 | package observer 2 | 3 | import ( 4 | "context" 5 | "strconv" 6 | "sync" 7 | ) 8 | 9 | type Stream[T any] interface { 10 | Subscribe() (ch <-chan *Block[T], closer func()) 11 | } 12 | 13 | type BlocksStream[T any] struct { 14 | connections map[string]chan *Block[T] 15 | mu *sync.RWMutex 16 | 17 | isWork bool 18 | cancelObserve context.CancelFunc 19 | } 20 | 21 | func NewBlocksStream[T any]() *BlocksStream[T] { 22 | return &BlocksStream[T]{ 23 | connections: make(map[string]chan *Block[T]), 24 | mu: &sync.RWMutex{}, 25 | } 26 | } 27 | 28 | func (b *BlocksStream[T]) Observe(ctx context.Context, blocks <-chan *Block[T]) { 29 | if b.isWork { 30 | return 31 | } 32 | 33 | // ctxObserve using for nested control process without stopped primary context 34 | ctxObserve, cancel := context.WithCancel(ctx) 35 | b.cancelObserve = cancel 36 | 37 | go func() { 38 | defer func() { 39 | b.mu.Lock() 40 | for connName := range b.connections { 41 | b.closeChannel(connName) 42 | } 43 | b.mu.Unlock() 44 | }() 45 | 46 | b.isWork = true 47 | 48 | for { 49 | select { 50 | case <-ctxObserve.Done(): 51 | // If primary context is done then cancel ctxObserver 52 | b.cancelObserve() 53 | return 54 | 55 | case block, ok := <-blocks: 56 | if !ok { 57 | return 58 | } 59 | 60 | b.mu.RLock() 61 | for _, connection := range b.connections { 62 | connection <- block 63 | } 64 | b.mu.RUnlock() 65 | } 66 | } 67 | }() 68 | } 69 | 70 | func (b *BlocksStream[T]) Subscribe() (<-chan *Block[T], func()) { 71 | b.mu.Lock() 72 | newConnection := make(chan *Block[T]) 73 | name := "channel-" + strconv.Itoa(len(b.connections)) 74 | b.connections[name] = newConnection 75 | b.mu.Unlock() 76 | 77 | closer := func() { b.closeChannel(name) } 78 | 79 | return newConnection, closer 80 | } 81 | 82 | func (b *BlocksStream[T]) closeChannel(name string) { 83 | b.mu.Lock() 84 | close(b.connections[name]) 85 | delete(b.connections, name) 86 | b.mu.Unlock() 87 | } 88 | 89 | func (b *BlocksStream[T]) Stop() { 90 | if b.cancelObserve != nil { 91 | b.cancelObserve() 92 | } 93 | b.isWork = false 94 | } 95 | -------------------------------------------------------------------------------- /observer/suite_test.go: -------------------------------------------------------------------------------- 1 | package observer_test 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestObservers(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Observers Suite") 13 | } 14 | 15 | var _ = BeforeSuite(func() { 16 | channelsBlocksPeerCommonTestBeforeSuit() 17 | channelsBlocksPeerParsedTestBeforeSuit() 18 | }) 19 | -------------------------------------------------------------------------------- /service/ccpackage/fetcher/fetcher.go: -------------------------------------------------------------------------------- 1 | package fetcher 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/url" 8 | "strings" 9 | 10 | "go.uber.org/zap" 11 | ) 12 | 13 | const ( 14 | FileProtocolPrefix = `file://` 15 | GitProtocolPrefix = `https://` 16 | LocalMountProtocolPrefix = `local://` 17 | ) 18 | 19 | var ( 20 | ErrUnknownProtocol = errors.New(`unknown protocol`) 21 | ) 22 | 23 | type Fetcher interface { 24 | // Fetch code by presented path and returns tar representation 25 | Fetch(ctx context.Context, repo, version string) ([]byte, error) 26 | } 27 | 28 | // Fetch repo from file path , git repo 29 | // file - file://path/to/repo 30 | // git repo with basic auth and token - https://{user}:{pass}@github.com/s7techlab/{repo}.git 31 | // git repo with token - https://{token}@github.com/s7techlab/{repo}.git 32 | func Fetch(ctx context.Context, repo, version string, logger *zap.Logger) ([]byte, error) { 33 | f, err := Create(repo, logger) 34 | if err != nil { 35 | return nil, fmt.Errorf("fetcher get: %w", err) 36 | } 37 | 38 | return f.Fetch(ctx, repo, version) 39 | } 40 | 41 | // Create returns Fetcher instance by repo scheme 42 | // Scheme file:// returns FileFetcher 43 | // Scheme https:// returns GitFetcher 44 | // Scheme local:// returns Local mount fetcher 45 | // git repo with basic auth and token - https://{user}:{pass}@github.com/s7techlab/{repo}.git 46 | // git repo with token - https://{token}@github.com/s7techlab/{repo}.git 47 | // Returns non-fetcher for unrecognized scheme 48 | func Create(repo string, l *zap.Logger) (Fetcher, error) { 49 | switch { 50 | case strings.HasPrefix(repo, FileProtocolPrefix): 51 | return NewFile(l), nil 52 | case strings.HasPrefix(repo, GitProtocolPrefix): 53 | var opts []GitOpt 54 | // Set auth options for repository if provided 55 | u, err := url.Parse(repo) 56 | if err != nil { 57 | return nil, fmt.Errorf("parse repo url: %w", err) 58 | } 59 | if p, set := u.User.Password(); set { 60 | opts = append(opts, GitBasicAuth(u.User.Username(), p)) 61 | } else if u.User.Username() != `` { 62 | opts = append(opts, GitTokenAuth(u.User.Username())) 63 | } 64 | opts = append(opts, WithLogger(l)) 65 | return NewGit(opts...), nil 66 | case strings.HasPrefix(repo, LocalMountProtocolPrefix): 67 | return NewNope(), nil 68 | 69 | default: 70 | return nil, ErrUnknownProtocol 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /service/ccpackage/fetcher/file.go: -------------------------------------------------------------------------------- 1 | package fetcher 2 | 3 | import ( 4 | "archive/tar" 5 | "bytes" 6 | "context" 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/go-git/go-billy/v5/osfs" 11 | "go.uber.org/zap" 12 | ) 13 | 14 | type File struct { 15 | Logger *zap.Logger 16 | } 17 | 18 | func NewFile(l *zap.Logger) *File { 19 | return &File{ 20 | Logger: l, 21 | } 22 | } 23 | 24 | func (f *File) Fetch(ctx context.Context, path, _ string) (code []byte, err error) { 25 | bf := new(bytes.Buffer) 26 | tw := tar.NewWriter(bf) 27 | 28 | defer func() { 29 | twErr := tw.Close() 30 | if err == nil && twErr != nil { 31 | err = fmt.Errorf("close tar writer: %w", err) 32 | } 33 | }() 34 | 35 | path = strings.TrimPrefix(path, FileProtocolPrefix) 36 | 37 | fs := osfs.New(path) 38 | 39 | f.Logger.Debug(`adding path to tar`, zap.String(`path`, path)) 40 | 41 | if err = AddFileToTar(tw, `/`, fs); err != nil { 42 | err = fmt.Errorf("fetch filepath=%s to tar: %w", path, err) 43 | return 44 | } 45 | 46 | return bf.Bytes(), nil 47 | } 48 | -------------------------------------------------------------------------------- /service/ccpackage/fetcher/file_test.go: -------------------------------------------------------------------------------- 1 | package fetcher_test 2 | 3 | import ( 4 | "archive/tar" 5 | "bytes" 6 | "context" 7 | "io" 8 | "path/filepath" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "go.uber.org/zap" 13 | 14 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage/fetcher" 15 | ) 16 | 17 | func TestFileFetcher_Fetch(t *testing.T) { 18 | f := fetcher.NewFile(zap.NewNop()) 19 | assert.NotNil(t, f) 20 | 21 | abs, err := filepath.Abs(`../`) 22 | assert.NoError(t, err) 23 | 24 | code, err := f.Fetch(context.Background(), abs+`/`, `some ver`) 25 | assert.NoError(t, err) 26 | assert.NotNil(t, code) 27 | assert.NoError(t, expectTar(code)) 28 | } 29 | 30 | func expectTar(b []byte) error { 31 | r := bytes.NewReader(b) 32 | tr := tar.NewReader(r) 33 | for { 34 | _, err := tr.Next() 35 | if err != nil { 36 | if err == io.EOF { 37 | return nil 38 | } 39 | return err 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /service/ccpackage/fetcher/nope.go: -------------------------------------------------------------------------------- 1 | package fetcher 2 | 3 | import "context" 4 | 5 | // Nope do nothing 6 | type Nope struct { 7 | } 8 | 9 | func (n *Nope) Fetch(ctx context.Context, repo, version string) ([]byte, error) { 10 | return nil, nil 11 | } 12 | 13 | func NewNope() *Nope { 14 | return &Nope{} 15 | } 16 | -------------------------------------------------------------------------------- /service/ccpackage/fetcher/tar.go: -------------------------------------------------------------------------------- 1 | package fetcher 2 | 3 | import ( 4 | "archive/tar" 5 | "fmt" 6 | "io" 7 | fsPath "path" 8 | 9 | "github.com/go-git/go-billy/v5" 10 | ) 11 | 12 | func AddFileToTar(tw *tar.Writer, path string, fs billy.Filesystem) error { 13 | files, err := fs.ReadDir(path) 14 | if err != nil { 15 | return fmt.Errorf("failed to read dir: %w", err) 16 | } 17 | 18 | if err = tw.WriteHeader(&tar.Header{ 19 | Typeflag: tar.TypeDir, 20 | Name: path, 21 | Mode: defaultMode, 22 | }); err != nil { 23 | return fmt.Errorf("failed to write tar header: %w", err) 24 | } 25 | 26 | for _, f := range files { 27 | fPath := fsPath.Join(path, f.Name()) 28 | if f.IsDir() { 29 | if f.Name()[0:1] == `.` { 30 | continue 31 | } 32 | if err = AddFileToTar(tw, fPath, fs); err != nil { 33 | return fmt.Errorf("failed to write path %s: %w", fPath, err) 34 | } 35 | continue 36 | } 37 | 38 | if err = tw.WriteHeader(&tar.Header{ 39 | Name: fPath, 40 | Size: f.Size(), 41 | Mode: defaultMode, 42 | ModTime: f.ModTime(), 43 | }); err != nil { 44 | return fmt.Errorf("failed to write tar header: %w", err) 45 | } 46 | file, err := fs.Open(fPath) 47 | if err != nil { 48 | return fmt.Errorf("failed to read file: %w", err) 49 | } 50 | if _, err = io.Copy(tw, file); err != nil { 51 | file.Close() 52 | return fmt.Errorf("failed to write file to tar: %w", err) 53 | } 54 | file.Close() 55 | } 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /service/ccpackage/packer/docker/tar.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "archive/tar" 5 | "bytes" 6 | "errors" 7 | "io" 8 | ) 9 | 10 | var ErrFileNotFound = errors.New(`file not found`) 11 | 12 | func UnTarFirstFile(r io.Reader) (*bytes.Buffer, error) { 13 | tr := tar.NewReader(r) 14 | file := new(bytes.Buffer) 15 | 16 | header, err := tr.Next() 17 | 18 | switch { 19 | case header == nil: 20 | return nil, nil 21 | 22 | case err != nil: 23 | return nil, err 24 | } 25 | 26 | switch header.Typeflag { 27 | case tar.TypeReg: 28 | if _, err := io.CopyN(file, tr, header.Size); err != nil { 29 | return nil, err 30 | } 31 | return file, nil 32 | 33 | default: 34 | return nil, ErrFileNotFound 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /service/ccpackage/packer/packer.go: -------------------------------------------------------------------------------- 1 | package packer 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage" 7 | ) 8 | 9 | type ( 10 | Packer interface { 11 | PackFromTar(ctx context.Context, spec *ccpackage.PackageSpec, tar []byte) (*ccpackage.Package, error) 12 | PackFromFiles(ctx context.Context, spec *ccpackage.PackageSpec, path string) (*ccpackage.Package, error) 13 | } 14 | 15 | PackFromTarRequest struct { 16 | } 17 | 18 | PackFromFileRequest struct { 19 | } 20 | ) 21 | -------------------------------------------------------------------------------- /service/ccpackage/store/file/file.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "os" 10 | "path/filepath" 11 | 12 | "google.golang.org/protobuf/types/known/timestamppb" 13 | 14 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage" 15 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage/store" 16 | ) 17 | 18 | type Params struct { 19 | RootPath string `mapstructure:"root_path"` 20 | } 21 | 22 | type Store struct { 23 | rootPath string 24 | perm os.FileMode 25 | } 26 | 27 | func New(ps Params) *Store { 28 | return &Store{ 29 | rootPath: ps.RootPath, 30 | perm: 0644, 31 | } 32 | } 33 | 34 | func (s *Store) filePath(id *ccpackage.PackageID) string { 35 | return filepath.Join(s.rootPath, store.ObjectKey(id)) 36 | } 37 | 38 | func (s *Store) Put(ctx context.Context, req *ccpackage.PutPackageRequest) error { 39 | return os.WriteFile(s.filePath(req.Id), req.Data, s.perm) 40 | } 41 | 42 | // Get gets chaincode package info from storage. 43 | func (s *Store) Get(_ context.Context, id *ccpackage.PackageID) (*ccpackage.Package, error) { 44 | fStat, err := os.Stat(s.filePath(id)) 45 | if err != nil { 46 | if errors.Is(err, os.ErrNotExist) { 47 | return nil, store.ErrPackageNotFound 48 | } 49 | return nil, fmt.Errorf("stat file: %w", err) 50 | } 51 | 52 | return &ccpackage.Package{ 53 | Id: id, 54 | Size: fStat.Size(), 55 | CreatedAt: timestamppb.New(fStat.ModTime()), 56 | }, nil 57 | } 58 | 59 | // List gets stored chaincode packages' infos. 60 | func (s *Store) List(ctx context.Context) ([]*ccpackage.Package, error) { 61 | fs, err := ioutil.ReadDir(s.rootPath) 62 | if err != nil { 63 | return nil, fmt.Errorf("read root path: %w", err) 64 | } 65 | 66 | var ps []*ccpackage.Package 67 | 68 | for _, f := range fs { 69 | 70 | if f.IsDir() { 71 | continue 72 | } 73 | 74 | name, version, fabricVersion, ok := store.ParseObjectKey(f.Name()) 75 | if !ok { 76 | continue 77 | } 78 | 79 | ps = append(ps, &ccpackage.Package{ 80 | Id: &ccpackage.PackageID{ 81 | Name: name, 82 | Version: version, 83 | FabricVersion: fabricVersion, 84 | }, 85 | Size: f.Size(), 86 | CreatedAt: timestamppb.New(f.ModTime()), 87 | }) 88 | } 89 | 90 | return ps, nil 91 | } 92 | 93 | // Fetch fetches chaincode package. 94 | func (s *Store) Fetch(ctx context.Context, id *ccpackage.PackageID) (io.ReadCloser, error) { 95 | return os.Open(s.filePath(id)) 96 | } 97 | 98 | func (s *Store) Close() error { 99 | return nil 100 | } 101 | -------------------------------------------------------------------------------- /service/ccpackage/store/memory/memory_test.go: -------------------------------------------------------------------------------- 1 | package memory_test 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "testing" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | 11 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage" 12 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage/store" 13 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage/store/memory" 14 | ) 15 | 16 | func TestMemoryStorage(t *testing.T) { 17 | RegisterFailHandler(Fail) 18 | RunSpecs(t, "Memory storage test suite") 19 | } 20 | 21 | var ( 22 | m *memory.Storage 23 | 24 | packageID1 = &ccpackage.PackageID{ 25 | Name: "cc", 26 | Version: "v1", 27 | FabricVersion: ccpackage.FabricVersion_FABRIC_V2, 28 | } 29 | 30 | packageData1 = []byte(`aaaaaaaaasonmebytes`) 31 | ) 32 | 33 | var _ = Describe("Memory package storage", func() { 34 | 35 | ctx := context.Background() 36 | 37 | It("allow to init", func() { 38 | m = memory.New() 39 | Expect(m).NotTo(BeNil()) 40 | }) 41 | 42 | It("allow to put item", func() { 43 | err := m.Put(ctx, &ccpackage.PutPackageRequest{ 44 | Id: packageID1, 45 | Data: packageData1, 46 | }) 47 | 48 | Expect(err).NotTo(HaveOccurred()) 49 | }) 50 | 51 | It("allow to get item", func() { 52 | p, err := m.Get(ctx, packageID1) 53 | 54 | Expect(err).NotTo(HaveOccurred()) 55 | Expect(p.Id.String()).To(Equal(packageID1.String())) 56 | Expect(int(p.Size)).To(Equal(len(packageData1))) 57 | }) 58 | 59 | It("should returns error for unknown package", func() { 60 | _, err := m.Get(ctx, &ccpackage.PackageID{ 61 | Name: "xxx", 62 | Version: "xxx", 63 | FabricVersion: 0, 64 | }) 65 | Expect(err).To(MatchError(store.ErrPackageNotFound)) 66 | }) 67 | 68 | It("allow to fetch item multiple times", func() { 69 | for i := 0; i < 3; i++ { 70 | data, err := m.Fetch(ctx, packageID1) 71 | Expect(err).NotTo(HaveOccurred()) 72 | 73 | bytes, err := io.ReadAll(data) 74 | 75 | Expect(err).NotTo(HaveOccurred()) 76 | Expect(bytes).To(Equal(packageData1)) 77 | } 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /service/ccpackage/store/storage.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "regexp" 8 | 9 | "github.com/s7techlab/hlf-sdk-go/service/ccpackage" 10 | ) 11 | 12 | var ( 13 | ErrPackageNotFound = fmt.Errorf("package not found") 14 | 15 | objectNameRegexp = regexp.MustCompile(`^([^_\s]+)_([^_\s]+)_([^_\s]+)\.pkg$`) 16 | ) 17 | 18 | const ( 19 | TypeS3 = "s3" 20 | TypeFile = "file" 21 | TypeMemory = "memory" 22 | ) 23 | 24 | type ( 25 | Storage interface { 26 | // Put saves chaincode package into storage. 27 | Put(context.Context, *ccpackage.PutPackageRequest) error 28 | // Get gets chaincode package info from storage. 29 | Get(context.Context, *ccpackage.PackageID) (*ccpackage.Package, error) 30 | // List gets stored chaincode packages' infos. 31 | List(context.Context) ([]*ccpackage.Package, error) 32 | // Fetch fetches chaincode package. 33 | Fetch(context.Context, *ccpackage.PackageID) (io.ReadCloser, error) 34 | // Close closes storage 35 | Close() error 36 | } 37 | ) 38 | 39 | func ParseObjectKey(s string) ( 40 | name string, 41 | version string, 42 | fabricVersion ccpackage.FabricVersion, 43 | ok bool, 44 | ) { 45 | ss := objectNameRegexp.FindStringSubmatch(s) 46 | if len(ss) != 4 { 47 | return "", "", ccpackage.FabricVersion_FABRIC_VERSION_UNSPECIFIED, false 48 | } 49 | return ss[1], ss[2], ccpackage.FabricVersion(ccpackage.FabricVersion_value[ss[3]]), true 50 | } 51 | 52 | func ObjectKey(id *ccpackage.PackageID) string { 53 | return fmt.Sprintf("%s_%s_%s.pkg", id.Name, id.Version, id.FabricVersion) 54 | } 55 | -------------------------------------------------------------------------------- /service/service.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/grpc-ecosystem/grpc-gateway/runtime" 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | type ( 11 | RegisterHandlerFromEndpoint func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) 12 | 13 | Def struct { 14 | name string 15 | swagger []byte 16 | Desc *grpc.ServiceDesc 17 | Service interface{} 18 | HandlerFromEndpointRegister RegisterHandlerFromEndpoint 19 | } 20 | ) 21 | 22 | func NewDef(name string, swagger []byte, desc *grpc.ServiceDesc, service interface{}, registerHandler RegisterHandlerFromEndpoint) *Def { 23 | return &Def{ 24 | name: name, 25 | swagger: swagger, 26 | Desc: desc, 27 | Service: service, 28 | HandlerFromEndpointRegister: registerHandler, 29 | } 30 | } 31 | 32 | func (s *Def) Name() string { 33 | return s.name 34 | } 35 | 36 | func (s *Def) Swagger() []byte { 37 | return s.swagger 38 | } 39 | 40 | func (s *Def) GRPCDesc() *grpc.ServiceDesc { 41 | return s.Desc 42 | } 43 | 44 | func (s *Def) Impl() interface{} { 45 | return s.Service 46 | } 47 | 48 | func (s *Def) GRPCGatewayRegister() func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { 49 | return s.HandlerFromEndpointRegister 50 | } 51 | -------------------------------------------------------------------------------- /service/systemcc/cscc/cscc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hlfsdk.service.systemcc.cscc; 4 | 5 | option go_package = "github.com/s7techlab/hlf-sdk-go/service/systemcc/cscc"; 6 | 7 | 8 | import "hyperledger/fabric-protos/common/common.proto"; 9 | import "hyperledger/fabric-protos/common/configtx.proto"; 10 | import "hyperledger/fabric-protos/peer/query.proto"; 11 | 12 | import "google/protobuf/empty.proto"; 13 | import "google/api/annotations.proto"; 14 | 15 | service CSCCService { 16 | 17 | // GetChainInfo allows joining channel using presented genesis block 18 | rpc JoinChain (JoinChainRequest) returns (google.protobuf.Empty) { 19 | option (google.api.http) = { 20 | post: "/systemcc/cscc/joinchain" 21 | body: "*" 22 | }; 23 | } 24 | 25 | rpc GetChannels(google.protobuf.Empty) returns (protos.ChannelQueryResponse) { 26 | option (google.api.http) = { 27 | get: "/systemcc/cscc/chains" 28 | }; 29 | } 30 | 31 | // GetConfigBlock returns genesis block of channel 32 | rpc GetConfigBlock (GetConfigBlockRequest) returns (common.Block) { 33 | option (google.api.http) = { 34 | get: "/systemcc/cscc/chains/{channel}" 35 | }; 36 | } 37 | 38 | // GetChannelConfig returns channel configuration 39 | rpc GetChannelConfig (GetChannelConfigRequest) returns (common.Config) { 40 | option (google.api.http) = { 41 | get: "/systemcc/cscc/chains/{channel}/config" 42 | }; 43 | } 44 | } 45 | 46 | message JoinChainRequest{ 47 | string channel = 1; 48 | common.Block genesis_block = 2; 49 | } 50 | 51 | message GetConfigBlockRequest { 52 | string channel = 1; 53 | } 54 | 55 | message GetChannelConfigRequest { 56 | string channel = 1; 57 | } 58 | -------------------------------------------------------------------------------- /service/systemcc/qscc/qscc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package hlfsdk.service.systemcc.qscc; 4 | 5 | option go_package = "github.com/s7techlab/hlf-sdk-go/service/systemcc/qscc"; 6 | 7 | 8 | import "hyperledger/fabric-protos/common/ledger.proto"; 9 | import "hyperledger/fabric-protos/common/common.proto"; 10 | import "hyperledger/fabric-protos/peer/transaction.proto"; 11 | 12 | import "google/api/annotations.proto"; 13 | 14 | service QSCCService { 15 | 16 | // GetChainInfo allows getting common info about channel blockchain 17 | rpc GetChainInfo(GetChainInfoRequest) returns (common.BlockchainInfo) { 18 | option (google.api.http) = { 19 | get: "/systemcc/qscc/chain/{channel_name}" 20 | }; 21 | } 22 | 23 | // GetBlockByNumber allows getting block by number 24 | rpc GetBlockByNumber(GetBlockByNumberRequest) returns (common.Block) { 25 | option (google.api.http) = { 26 | get: "/systemcc/qscc/chain/{channel_name}/{block_number}" 27 | }; 28 | } 29 | 30 | // GetBlockByHash allows getting block by hash 31 | rpc GetBlockByHash(GetBlockByHashRequest) returns (common.Block) { 32 | option (google.api.http) = { 33 | get: "/systemcc/qscc/chain/{channel_name}/byhash/{block_hash}" 34 | }; 35 | } 36 | 37 | // GetBlockByTxID allows getting block by transaction 38 | rpc GetBlockByTxID (GetBlockByTxIDRequest) returns (common.Block) { 39 | option (google.api.http) = { 40 | get: "/systemcc/qscc/chain/{channel_name}/bytxid/{tx_id}" 41 | }; 42 | } 43 | 44 | // GetTransactionByID allows getting transaction by id 45 | rpc GetTransactionByID(GetTransactionByIDRequest) returns (protos.ProcessedTransaction) { 46 | option (google.api.http) = { 47 | get: "/systemcc/qscc/tx/{channel_name}/{tx_id}" 48 | }; 49 | } 50 | } 51 | 52 | message GetChainInfoRequest { 53 | string channel_name = 1; 54 | } 55 | 56 | message GetBlockByNumberRequest { 57 | string channel_name = 1; 58 | int64 block_number = 2; 59 | } 60 | 61 | message GetBlockByHashRequest { 62 | string channel_name = 1; 63 | bytes block_hash = 2; 64 | } 65 | 66 | message GetTransactionByIDRequest { 67 | string channel_name = 1; 68 | string tx_id = 2; 69 | } 70 | 71 | message GetBlockByTxIDRequest { 72 | string channel_name = 1; 73 | string tx_id = 2; 74 | } 75 | -------------------------------------------------------------------------------- /service/wallet/store.go: -------------------------------------------------------------------------------- 1 | package wallet 2 | 3 | type ( 4 | Store interface { 5 | Get(label string) (*IdentityInWallet, error) 6 | Set(identity *IdentityInWallet) error 7 | List() (labels []string, err error) 8 | Delete(label string) error 9 | } 10 | ) 11 | -------------------------------------------------------------------------------- /service/wallet/store/file/store.go: -------------------------------------------------------------------------------- 1 | package file 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "os" 8 | 9 | wallet2 "github.com/s7techlab/hlf-sdk-go/service/wallet" 10 | ) 11 | 12 | var ( 13 | ErrDirectoryNotExists = errors.New(`directory not exists`) 14 | ) 15 | 16 | type ( 17 | FilesystemStore struct { 18 | baseDir string 19 | } 20 | ) 21 | 22 | func New(baseDir string) (*FilesystemStore, error) { 23 | if baseDir == `` { 24 | return nil, fmt.Errorf(`dir= : %w`, ErrDirectoryNotExists) 25 | } 26 | 27 | if _, err := os.Stat(baseDir); os.IsNotExist(err) { 28 | return nil, fmt.Errorf(`dir= %s: %w`, baseDir, ErrDirectoryNotExists) 29 | } 30 | 31 | if baseDir[len(baseDir)-1:] != `/` { 32 | baseDir = baseDir + `/` 33 | } 34 | 35 | return &FilesystemStore{baseDir: baseDir}, nil 36 | } 37 | 38 | func (f *FilesystemStore) labelToFilename(label string) string { 39 | return f.baseDir + label + `.json` 40 | } 41 | 42 | func (f *FilesystemStore) filenameToLabel(filename string) string { 43 | if len(filename) < 6 { 44 | return `` 45 | } 46 | 47 | if filename[len(filename)-5:] != `.json` { 48 | return `` 49 | } 50 | return filename[0 : len(filename)-5] 51 | } 52 | 53 | func (f *FilesystemStore) Get(label string) (*wallet2.IdentityInWallet, error) { 54 | if _, err := os.Stat(f.labelToFilename(label)); os.IsNotExist(err) { 55 | return nil, wallet2.ErrIdentityNotFound 56 | } 57 | 58 | bb, err := os.ReadFile(f.labelToFilename(label)) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | identity := new(wallet2.IdentityInWallet) 64 | 65 | if err = json.Unmarshal(bb, identity); err != nil { 66 | return nil, err 67 | } 68 | 69 | return identity, nil 70 | } 71 | 72 | func (f *FilesystemStore) Set(identity *wallet2.IdentityInWallet) error { 73 | bb, err := json.Marshal(identity) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | return os.WriteFile(f.labelToFilename(identity.Label), bb, 0600) 79 | } 80 | 81 | func (f *FilesystemStore) List() ([]string, error) { 82 | var labels []string 83 | 84 | files, err := os.ReadDir(f.baseDir) 85 | if err != nil { 86 | return nil, fmt.Errorf(`reading %s: %w`, f.baseDir, err) 87 | } 88 | 89 | for _, file := range files { 90 | if label := f.filenameToLabel(file.Name()); label != `` { 91 | labels = append(labels, label) 92 | } 93 | } 94 | return labels, nil 95 | } 96 | 97 | func (f *FilesystemStore) Delete(label string) error { 98 | if _, err := os.Stat(f.labelToFilename(label)); os.IsNotExist(err) { 99 | return wallet2.ErrIdentityNotFound 100 | } 101 | 102 | return os.Remove(f.labelToFilename(label)) 103 | } 104 | -------------------------------------------------------------------------------- /service/wallet/store/memory/store.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | wallet2 "github.com/s7techlab/hlf-sdk-go/service/wallet" 5 | ) 6 | 7 | type ( 8 | MemoryStore struct { 9 | identities map[string]*wallet2.IdentityInWallet 10 | } 11 | ) 12 | 13 | func New() *MemoryStore { 14 | return &MemoryStore{ 15 | identities: make(map[string]*wallet2.IdentityInWallet), 16 | } 17 | } 18 | 19 | func (ms *MemoryStore) Get(label string) (*wallet2.IdentityInWallet, error) { 20 | id, exists := ms.identities[label] 21 | if !exists { 22 | return nil, wallet2.ErrIdentityNotFound 23 | } 24 | 25 | return id, nil 26 | } 27 | 28 | func (ms *MemoryStore) Set(identity *wallet2.IdentityInWallet) error { 29 | ms.identities[identity.Label] = identity 30 | return nil 31 | } 32 | 33 | func (ms *MemoryStore) List() ([]string, error) { 34 | var labels []string 35 | 36 | for l := range ms.identities { 37 | labels = append(labels, l) 38 | } 39 | 40 | return labels, nil 41 | } 42 | 43 | func (ms *MemoryStore) Delete(label string) error { 44 | delete(ms.identities, label) 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /testdata/blocks/blocks.go: -------------------------------------------------------------------------------- 1 | package blocks 2 | 3 | const ( 4 | Path = "testdata/blocks/fixtures" 5 | 6 | SampleChannel = "sample-channel" 7 | SampleChannelHeight uint64 = 10 8 | FabcarChannel = "fabcar-channel" 9 | FabcarChannelHeight uint64 = 12 10 | 11 | SampleChaincode = "sample" 12 | FabcarChaincode = "fabcar" 13 | ) 14 | 15 | var ( 16 | Channels = []string{SampleChannel, FabcarChannel} 17 | ChannelsHeights = map[string]uint64{SampleChannel: SampleChannelHeight, FabcarChannel: FabcarChannelHeight} 18 | 19 | Chaincodes = []string{SampleChaincode, FabcarChaincode} 20 | ) 21 | -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/0.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/0.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/1.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/1.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/10.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/10.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/11.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/11.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/2.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/2.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/3.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/3.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/4.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/4.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/5.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/5.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/6.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/6.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/7.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/7.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/8.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/8.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/fabcar-channel/9.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/fabcar-channel/9.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/0.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/0.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/1.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/1.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/2.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/2.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/3.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/3.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/4.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/4.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/5.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/5.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/6.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/6.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/7.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/7.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/8.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/8.pb -------------------------------------------------------------------------------- /testdata/blocks/fixtures/sample-channel/9.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/s7techlab/hlf-sdk-go/5d771c341a01fad6550a40d3fa6f48edaf634d3c/testdata/blocks/fixtures/sample-channel/9.pb -------------------------------------------------------------------------------- /third_party/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | breaking: 3 | use: 4 | - FILE 5 | lint: 6 | use: 7 | - MINIMAL 8 | except: 9 | - PACKAGE_DIRECTORY_MATCH -------------------------------------------------------------------------------- /third_party/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/common/ledger.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/common"; 8 | option java_package = "org.hyperledger.fabric.protos.common"; 9 | 10 | package common; 11 | 12 | // Contains information about the blockchain ledger such as height, current 13 | // block hash, and previous block hash. 14 | message BlockchainInfo { 15 | uint64 height = 1; 16 | bytes currentBlockHash = 2; 17 | bytes previousBlockHash = 3; 18 | // Specifies bootstrapping snapshot info if the channel is bootstrapped from a snapshot. 19 | // It is nil if the channel is not bootstrapped from a snapshot. 20 | BootstrappingSnapshotInfo bootstrappingSnapshotInfo = 4; 21 | } 22 | 23 | // Contains information for the bootstrapping snapshot. 24 | message BootstrappingSnapshotInfo { 25 | uint64 lastBlockInSnapshot = 1; 26 | } 27 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/ledger/queryresult/kv_query_result.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | package queryresult; 8 | 9 | option go_package = "github.com/hyperledger/fabric-protos-go/ledger/queryresult"; 10 | option java_package = "org.hyperledger.fabric.protos.ledger.queryresult"; 11 | 12 | import "google/protobuf/timestamp.proto"; 13 | 14 | 15 | // KV -- QueryResult for range/execute query. Holds a key and corresponding value. 16 | message KV { 17 | string namespace = 1; 18 | string key = 2; 19 | bytes value = 3; 20 | } 21 | 22 | // KeyModification -- QueryResult for history query. Holds a transaction ID, value, 23 | // timestamp, and delete marker which resulted from a history query. 24 | message KeyModification { 25 | string tx_id = 1; 26 | bytes value = 2; 27 | google.protobuf.Timestamp timestamp = 3; 28 | bool is_delete = 4; 29 | } 30 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/ledger/rwset/rwset.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/ledger/rwset"; 8 | option java_package = "org.hyperledger.fabric.protos.ledger.rwset"; 9 | 10 | package rwset; 11 | 12 | // TxReadWriteSet encapsulates a read-write set for a transaction 13 | // DataModel specifies the enum value of the data model 14 | // ns_rwset field specifies a list of chaincode specific read-write set (one for each chaincode) 15 | message TxReadWriteSet { 16 | enum DataModel { 17 | KV = 0; 18 | } 19 | DataModel data_model = 1; 20 | repeated NsReadWriteSet ns_rwset = 2; 21 | } 22 | 23 | // NsReadWriteSet encapsulates the read-write set for a chaincode 24 | message NsReadWriteSet { 25 | string namespace = 1; 26 | bytes rwset = 2; // Data model specific serialized proto message (e.g., kvrwset.KVRWSet for KV and Document data models) 27 | repeated CollectionHashedReadWriteSet collection_hashed_rwset = 3; 28 | } 29 | 30 | // CollectionHashedReadWriteSet encapsulate the hashed representation for the private read-write set for a collection 31 | message CollectionHashedReadWriteSet { 32 | string collection_name = 1; 33 | bytes hashed_rwset = 2; // Data model specific serialized proto message (e.g., kvrwset.HashedRWSet for KV and Document data models) 34 | bytes pvt_rwset_hash = 3; // Hash of entire private read-write set for a specific collection. This helps in authenticating the private read-write set efficiently 35 | } 36 | 37 | // TxPvtReadWriteSet encapsulate the private read-write set for a transaction 38 | message TxPvtReadWriteSet { 39 | TxReadWriteSet.DataModel data_model = 1; 40 | repeated NsPvtReadWriteSet ns_pvt_rwset = 2; 41 | } 42 | 43 | // NsPvtReadWriteSet encapsulates the private read-write set for a chaincode 44 | message NsPvtReadWriteSet { 45 | string namespace = 1; 46 | repeated CollectionPvtReadWriteSet collection_pvt_rwset = 2; 47 | } 48 | 49 | // CollectionPvtReadWriteSet encapsulates the private read-write set for a collection 50 | message CollectionPvtReadWriteSet { 51 | string collection_name = 1; 52 | bytes rwset = 2; // Data model specific serialized proto message (e.g., kvrwset.KVRWSet for KV and Document data models) 53 | } 54 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/msp/identities.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/msp"; 8 | option java_package = "org.hyperledger.fabric.protos.msp"; 9 | 10 | package msp; 11 | 12 | // This struct represents an Identity 13 | // (with its MSP identifier) to be used 14 | // to serialize it and deserialize it 15 | message SerializedIdentity { 16 | // The identifier of the associated membership service provider 17 | string mspid = 1; 18 | 19 | // the Identity, serialized according to the rules of its MPS 20 | bytes id_bytes = 2; 21 | } 22 | 23 | // This struct represents an Idemix Identity 24 | // to be used to serialize it and deserialize it. 25 | // The IdemixMSP will first serialize an idemix identity to bytes using 26 | // this proto, and then uses these bytes as id_bytes in SerializedIdentity 27 | message SerializedIdemixIdentity { 28 | // nym_x is the X-component of the pseudonym elliptic curve point. 29 | // It is a []byte representation of an amcl.BIG 30 | // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. 31 | bytes nym_x = 1; 32 | 33 | // nym_y is the Y-component of the pseudonym elliptic curve point. 34 | // It is a []byte representation of an amcl.BIG 35 | // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. 36 | bytes nym_y = 2; 37 | 38 | // ou contains the organizational unit of the idemix identity 39 | bytes ou = 3; 40 | 41 | // role contains the role of this identity (e.g., ADMIN or MEMBER) 42 | bytes role = 4; 43 | 44 | // proof contains the cryptographic evidence that this identity is valid 45 | bytes proof = 5; 46 | } 47 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/orderer/cluster.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/orderer"; 8 | option java_package = "org.hyperledger.fabric.protos.orderer"; 9 | 10 | package orderer; 11 | 12 | import "common/common.proto"; 13 | 14 | // Cluster defines communication between cluster members. 15 | service Cluster { 16 | // Step passes an implementation-specific message to another cluster member. 17 | rpc Step(stream StepRequest) returns (stream StepResponse); 18 | } 19 | 20 | // StepRequest wraps a message that is sent to a cluster member. 21 | message StepRequest { 22 | oneof payload { 23 | // consensus_request is a consensus specific message. 24 | ConsensusRequest consensus_request = 1; 25 | // submit_request is a relay of a transaction. 26 | SubmitRequest submit_request = 2; 27 | } 28 | } 29 | 30 | // StepResponse is a message received from a cluster member. 31 | message StepResponse { 32 | oneof payload { 33 | SubmitResponse submit_res = 1; 34 | } 35 | } 36 | 37 | // ConsensusRequest is a consensus specific message sent to a cluster member. 38 | message ConsensusRequest { 39 | string channel = 1; 40 | bytes payload = 2; 41 | bytes metadata = 3; 42 | } 43 | 44 | // SubmitRequest wraps a transaction to be sent for ordering. 45 | message SubmitRequest { 46 | string channel = 1; 47 | // last_validation_seq denotes the last 48 | // configuration sequence at which the 49 | // sender validated this message. 50 | uint64 last_validation_seq = 2; 51 | // content is the fabric transaction 52 | // that is forwarded to the cluster member. 53 | common.Envelope payload = 3; 54 | } 55 | 56 | // SubmitResponse returns a success 57 | // or failure status to the sender. 58 | message SubmitResponse { 59 | string channel = 1; 60 | // Status code, which may be used to programatically respond to success/failure. 61 | common.Status status = 2; 62 | // Info string which may contain additional information about the returned status. 63 | string info = 3; 64 | } 65 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/orderer/configuration.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/orderer"; 8 | option java_package = "org.hyperledger.fabric.protos.orderer"; 9 | 10 | package orderer; 11 | 12 | // The orderer config is specified by the following convention: 13 | // For a configuration item with key "Key" 14 | // the encoded value is a a proto message of type "Key" 15 | // For example, for the configuration item of name "ConsensusType" 16 | // the encoded value is the proto message "ConsensusType" 17 | 18 | message ConsensusType { 19 | // The consensus type: "solo", "kafka" or "etcdraft". 20 | string type = 1; 21 | // Opaque metadata, dependent on the consensus type. 22 | bytes metadata = 2; 23 | 24 | // State defines the orderer mode of operation, typically for consensus-type migration. 25 | // NORMAL is during normal operation, when consensus-type migration is not, and can not, take place. 26 | // MAINTENANCE is when the consensus-type can be changed. 27 | enum State { 28 | STATE_NORMAL = 0; 29 | STATE_MAINTENANCE = 1; 30 | } 31 | // The state signals the ordering service to go into maintenance mode, typically for consensus-type migration. 32 | State state = 3; 33 | } 34 | 35 | message BatchSize { 36 | // Simply specified as number of messages for now, in the future 37 | // we may want to allow this to be specified by size in bytes 38 | uint32 max_message_count = 1; 39 | // The byte count of the serialized messages in a batch cannot 40 | // exceed this value. 41 | uint32 absolute_max_bytes = 2; 42 | // The byte count of the serialized messages in a batch should not 43 | // exceed this value. 44 | uint32 preferred_max_bytes = 3; 45 | } 46 | 47 | message BatchTimeout { 48 | // Any duration string parseable by ParseDuration(): 49 | // https://golang.org/pkg/time/#ParseDuration 50 | string timeout = 1; 51 | } 52 | 53 | // Carries a list of bootstrap brokers, i.e. this is not the exclusive set of 54 | // brokers an ordering service 55 | message KafkaBrokers { 56 | // Each broker here should be identified using the (IP|host):port notation, 57 | // e.g. 127.0.0.1:7050, or localhost:7050 are valid entries 58 | repeated string brokers = 1; 59 | } 60 | 61 | // ChannelRestrictions is the mssage which conveys restrictions on channel creation for an orderer 62 | message ChannelRestrictions { 63 | uint64 max_count = 1; // The max count of channels to allow to be created, a value of 0 indicates no limit 64 | } 65 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/orderer/etcdraft/configuration.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/orderer/etcdraft"; 8 | option java_package = "org.hyperledger.fabric.protos.orderer.etcdraft"; 9 | 10 | package etcdraft; 11 | 12 | // ConfigMetadata is serialized and set as the value of ConsensusType.Metadata in 13 | // a channel configuration when the ConsensusType.Type is set "etcdraft". 14 | message ConfigMetadata { 15 | repeated Consenter consenters = 1; 16 | Options options = 2; 17 | } 18 | 19 | // Consenter represents a consenting node (i.e. replica). 20 | message Consenter { 21 | string host = 1; 22 | uint32 port = 2; 23 | bytes client_tls_cert = 3; 24 | bytes server_tls_cert = 4; 25 | } 26 | 27 | // Options to be specified for all the etcd/raft nodes. These can be modified on a 28 | // per-channel basis. 29 | message Options { 30 | string tick_interval = 1; // time duration format, e.g. 500ms 31 | uint32 election_tick = 2; 32 | uint32 heartbeat_tick = 3; 33 | uint32 max_inflight_blocks = 4; 34 | // Take snapshot when cumulative data exceeds certain size in bytes. 35 | uint32 snapshot_interval_size = 5; 36 | } 37 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/orderer/etcdraft/metadata.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/orderer/etcdraft"; 8 | option java_package = "org.hyperledger.fabric.protos.orderer.etcdraft"; 9 | 10 | package etcdraft; 11 | 12 | // BlockMetadata stores data used by the Raft OSNs when 13 | // coordinating with each other, to be serialized into 14 | // block meta dta field and used after failres and restarts. 15 | message BlockMetadata { 16 | // Maintains a mapping between the cluster's OSNs 17 | // and their Raft IDs. 18 | repeated uint64 consenter_ids = 1; 19 | // Carries the Raft ID value that will be assigned 20 | // to the next OSN that will join this cluster. 21 | uint64 next_consenter_id = 2; 22 | // Index of etcd/raft entry for current block. 23 | uint64 raft_index = 3; 24 | } 25 | 26 | // ClusterMetadata encapsulates metadata that is exchanged among cluster nodes 27 | message ClusterMetadata { 28 | // Indicates active nodes in cluster that are reacheable by Raft leader 29 | repeated uint64 active_nodes = 1; 30 | } 31 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/chaincode_event.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option java_outer_classname = "ChaincodeEventPackage"; 9 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 10 | 11 | package protos; 12 | 13 | //ChaincodeEvent is used for events and registrations that are specific to chaincode 14 | //string type - "chaincode" 15 | message ChaincodeEvent { 16 | string chaincode_id = 1; 17 | string tx_id = 2; 18 | string event_name = 3; 19 | bytes payload = 4; 20 | } 21 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/configuration.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 9 | 10 | package protos; 11 | 12 | // AnchorPeers simply represents list of anchor peers which is used in ConfigurationItem 13 | message AnchorPeers { 14 | repeated AnchorPeer anchor_peers = 1; 15 | } 16 | 17 | // AnchorPeer message structure which provides information about anchor peer, it includes host name, 18 | // port number and peer certificate. 19 | message AnchorPeer { 20 | string host = 1; // DNS host name of the anchor peer 21 | int32 port = 2; // The port number 22 | } 23 | 24 | // APIResource represents an API resource in the peer whose ACL 25 | // is determined by the policy_ref field 26 | message APIResource { 27 | string policy_ref = 1; // The policy name to use for this API 28 | } 29 | 30 | // ACLs provides mappings for resources in a channel. APIResource encapsulates 31 | // reference to a policy used to determine ACL for the resource 32 | message ACLs { 33 | map acls = 1; 34 | } 35 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/lifecycle/chaincode_definition.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer.lifecycle"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer/lifecycle"; 9 | 10 | package lifecycle; 11 | 12 | // These protos are used for encoding chaincode definitions into the statedb 13 | // in general, it should not be necessary for clients to utilize them. 14 | 15 | // ChaincodeEndorsementInfo is (most) everything the peer needs to know in order 16 | // to execute a chaincode 17 | message ChaincodeEndorsementInfo { 18 | string version = 1; 19 | bool init_required = 2; 20 | string endorsement_plugin = 3; 21 | } 22 | 23 | // ValidationInfo is (most) everything the peer needs to know in order 24 | // to validate a transaction 25 | message ChaincodeValidationInfo { 26 | string validation_plugin = 1; 27 | bytes validation_parameter = 2; 28 | } 29 | 30 | // The notable omission in this file is the collection configuration info. 31 | // It should be moved to this package, but... defering for now. 32 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/lifecycle/db.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer.lifecycle"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer/lifecycle"; 9 | 10 | package lifecycle; 11 | 12 | // These protos are used for encoding data into the statedb 13 | // in general, it should not be necessary for clients to utilize them. 14 | 15 | // StateMetadata describes the keys in a namespace. It is necessary because 16 | // in collections, range scans are not possible during transactions which 17 | // write. Therefore we must track the keys in our namespace ourselves. 18 | message StateMetadata { 19 | string datatype = 1; 20 | repeated string fields = 2; 21 | } 22 | 23 | // StateData encodes a particular field of a datatype 24 | message StateData { 25 | oneof Type { 26 | int64 Int64 = 1; 27 | bytes Bytes = 2; 28 | string String = 3; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/peer.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 9 | 10 | package protos; 11 | 12 | import "peer/proposal.proto"; 13 | import "peer/proposal_response.proto"; 14 | 15 | service Endorser { 16 | rpc ProcessProposal(SignedProposal) returns (ProposalResponse); 17 | } 18 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/policy.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 8 | option java_package = "org.hyperledger.fabric.protos.peer"; 9 | 10 | package protos; 11 | 12 | import "hyperledger/fabric-protos/common/policies.proto"; 13 | 14 | // ApplicationPolicy captures the diffenrent policy types that 15 | // are set and evaluted at the application level. 16 | message ApplicationPolicy { 17 | oneof Type { 18 | // SignaturePolicy type is used if the policy is specified as 19 | // a combination (using threshold gates) of signatures from MSP 20 | // principals 21 | common.SignaturePolicyEnvelope signature_policy = 1; 22 | 23 | // ChannelConfigPolicyReference is used when the policy is 24 | // specified as a string that references a policy defined in 25 | // the configuration of the channel 26 | string channel_config_policy_reference = 2; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/query.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 9 | 10 | package protos; 11 | 12 | // ChaincodeQueryResponse returns information about each chaincode that pertains 13 | // to a query in lscc.go, such as GetChaincodes (returns all chaincodes 14 | // instantiated on a channel), and GetInstalledChaincodes (returns all chaincodes 15 | // installed on a peer) 16 | message ChaincodeQueryResponse { 17 | repeated ChaincodeInfo chaincodes = 1; 18 | } 19 | 20 | // ChaincodeInfo contains general information about an installed/instantiated 21 | // chaincode 22 | message ChaincodeInfo { 23 | string name = 1; 24 | string version = 2; 25 | // the path as specified by the install/instantiate transaction 26 | string path = 3; 27 | // the chaincode function upon instantiation and its arguments. This will be 28 | // blank if the query is returning information about installed chaincodes. 29 | string input = 4; 30 | // the name of the ESCC for this chaincode. This will be 31 | // blank if the query is returning information about installed chaincodes. 32 | string escc = 5; 33 | // the name of the VSCC for this chaincode. This will be 34 | // blank if the query is returning information about installed chaincodes. 35 | string vscc = 6; 36 | // the chaincode unique id. 37 | // computed as: H( 38 | // H(name || version) || 39 | // H(CodePackage) 40 | // ) 41 | bytes id = 7; 42 | } 43 | 44 | // ChannelQueryResponse returns information about each channel that pertains 45 | // to a query in lscc.go, such as GetChannels (returns all channels for a 46 | // given peer) 47 | message ChannelQueryResponse { 48 | repeated ChannelInfo channels = 1; 49 | } 50 | 51 | // ChannelInfo contains general information about channels 52 | message ChannelInfo { 53 | string channel_id = 1; 54 | } 55 | 56 | // JoinBySnapshotStatus contains information about whether or a JoinBySnapshot operation 57 | // is in progress and the related bootstrap dir if it is running. 58 | message JoinBySnapshotStatus { 59 | bool in_progress = 1; 60 | string bootstrapping_snapshot_dir = 2; 61 | } 62 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/signed_cc_dep_spec.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 9 | 10 | package protos; 11 | 12 | import "peer/proposal_response.proto"; 13 | 14 | // SignedChaincodeDeploymentSpec carries the CDS along with endorsements 15 | message SignedChaincodeDeploymentSpec { 16 | // This is the bytes of the ChaincodeDeploymentSpec 17 | bytes chaincode_deployment_spec = 1; 18 | 19 | // This is the instantiation policy which is identical in structure 20 | // to endorsement policy. This policy is checked by the VSCC at commit 21 | // time on the instantiation (all peers will get the same policy as it 22 | // will be part of the LSCC instantation record and will be part of the 23 | // hash as well) 24 | bytes instantiation_policy = 2; 25 | 26 | // The endorsements of the above deployment spec, the owner's signature over 27 | // chaincode_deployment_spec and Endorsement.endorser. 28 | repeated Endorsement owner_endorsements = 3; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/peer/snapshot.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 8 | option java_package = "org.hyperledger.fabric.protos.peer"; 9 | 10 | package protos; 11 | 12 | import "google/protobuf/empty.proto"; 13 | import "common/common.proto"; 14 | 15 | // SnapshotRequest contains information for a generate/cancel snapshot request 16 | message SnapshotRequest { 17 | // The signature header that contains creator identity and nonce 18 | common.SignatureHeader signature_header = 1; 19 | // The channel ID 20 | string channel_id = 2; 21 | // The block number to generate a snapshot 22 | uint64 block_number = 3; 23 | } 24 | 25 | // SnapshotQuery contains information for a query snapshot request 26 | message SnapshotQuery { 27 | // The signature header that contains creator identity and nonce 28 | common.SignatureHeader signature_header = 1; 29 | // The channel ID 30 | string channel_id = 2; 31 | } 32 | 33 | // SignedSnapshotRequest contains marshalled request bytes and signature 34 | message SignedSnapshotRequest { 35 | // The bytes of SnapshotRequest or SnapshotQuery 36 | bytes request = 1; 37 | // Signaure over request bytes; this signature is to be verified against the client identity 38 | bytes signature = 2; 39 | } 40 | 41 | // QueryPendingSnapshotsResponse specifies the response payload of a query pending snapshots request 42 | message QueryPendingSnapshotsResponse { 43 | repeated uint64 block_numbers = 1; 44 | } 45 | 46 | service Snapshot { 47 | // Generate a snapshot reqeust. SignedSnapshotRequest contains marshalled bytes for SnaphostRequest 48 | rpc Generate(SignedSnapshotRequest) returns (google.protobuf.Empty) {} 49 | // Cancel a snapshot reqeust. SignedSnapshotRequest contains marshalled bytes for SnaphostRequest 50 | rpc Cancel(SignedSnapshotRequest) returns (google.protobuf.Empty) {} 51 | // Query pending snapshots query. SignedSnapshotRequest contains marshalled bytes for SnaphostQuery 52 | rpc QueryPendings(SignedSnapshotRequest) returns (QueryPendingSnapshotsResponse) {} 53 | } 54 | -------------------------------------------------------------------------------- /third_party/hyperledger/fabric-protos/transientstore/transientstore.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | package transientstore; 8 | 9 | option go_package = "github.com/hyperledger/fabric-protos-go/transientstore"; 10 | option java_package = "org.hyperledger.fabric.protos.transientstore"; 11 | 12 | import "ledger/rwset/rwset.proto"; 13 | import "peer/collection.proto"; 14 | 15 | // TxPvtReadWriteSetWithConfigInfo encapsulates the transaction's private 16 | // read-write set and additional information about the configurations such as 17 | // the latest collection config when the transaction is simulated 18 | message TxPvtReadWriteSetWithConfigInfo { 19 | uint64 endorsed_at = 1; 20 | rwset.TxPvtReadWriteSet pvt_rwset = 2; 21 | map collection_configs = 3; 22 | } 23 | --------------------------------------------------------------------------------