├── .github
└── settings.yml
├── .gitignore
├── CHANGELOG.md
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── LICENSE
├── MAINTAINERS.txt
├── Makefile
├── README.md
├── ci
└── azure-pipelines.yml
├── dev
└── user.clj
├── docs
├── application-development.md
├── client-development.md
├── command-reference.md
├── getting-started.md
├── images
│ ├── readme-drawings.graffle
│ └── typical-workflow.png
├── index.md
├── interface.md
├── metadata.md
└── platforms
│ ├── golang.md
│ └── system.md
├── examples
├── example02
│ ├── README.md
│ ├── app
│ │ ├── chaincode.yaml
│ │ └── src
│ │ │ ├── chaincode
│ │ │ └── chaincode_example02.go
│ │ │ └── interfaces
│ │ │ ├── appinit.cci
│ │ │ └── org.hyperledger.chaincode.example02.cci
│ └── client
│ │ ├── cljs
│ │ ├── Makefile
│ │ ├── project.clj
│ │ ├── protos
│ │ │ ├── appinit.proto
│ │ │ └── org.hyperledger.chaincode.example02.proto
│ │ ├── sample.config
│ │ └── src
│ │ │ ├── example02
│ │ │ ├── api.cljs
│ │ │ ├── connection.cljs
│ │ │ ├── main.cljs
│ │ │ ├── protobuf.cljs
│ │ │ └── rpc.cljs
│ │ │ └── fabric_sdk
│ │ │ ├── channel.cljs
│ │ │ ├── core.cljs
│ │ │ ├── eventhub.cljs
│ │ │ ├── macros.clj
│ │ │ └── user.cljs
│ │ └── nodejs
│ │ ├── client.config
│ │ ├── client.js
│ │ ├── lib
│ │ └── util.js
│ │ ├── package.json
│ │ └── protos
│ │ ├── appinit.proto
│ │ └── org.hyperledger.chaincode.example02.proto
├── helloworld
│ ├── chaincode.yaml
│ └── src
│ │ ├── chaincode
│ │ └── main.go
│ │ ├── interfaces
│ │ ├── appinit.cci
│ │ └── org.hyperledger.chaincode.helloworld.cci
│ │ └── org
│ │ └── hyperledger
│ │ └── chaincode
│ │ └── helloworld
│ │ └── core.go
├── invoker
│ ├── chaincode.yaml
│ └── src
│ │ ├── chaincode
│ │ └── chaincode.go
│ │ └── interfaces
│ │ ├── appinit.cci
│ │ └── org.hyperledger.chaincode.example02.cci
├── parameterless
│ ├── chaincode.yaml
│ └── src
│ │ ├── chaincode
│ │ └── main.go
│ │ └── interfaces
│ │ ├── appinit.cci
│ │ └── org.hyperledger.chaincode.example.parameterless.cci
└── sample_syscc
│ ├── chaincode.yaml
│ ├── interfaces
│ ├── appinit.cci
│ └── org.hyperledger.chaincode.system.sample.cci
│ └── sample_syscc.go
├── lein
├── mkdocs.yml
├── project.clj
├── resources
├── generators
│ ├── golang.stg
│ └── proto.stg
├── metadata
│ └── org.hyperledger.chaintool.meta.cci
├── parsers
│ ├── interface
│ │ ├── grammar.bnf
│ │ └── skip.bnf
│ └── proto
│ │ ├── grammar.bnf
│ │ └── skip.bnf
└── proto
│ └── car.proto
├── scripts
└── changelog.sh
├── src
├── chaintool
│ ├── ast.clj
│ ├── build
│ │ ├── core.clj
│ │ └── interface.clj
│ ├── car
│ │ ├── abi
│ │ │ └── Car.java
│ │ ├── ls.clj
│ │ ├── read.clj
│ │ ├── types.clj
│ │ ├── unpack.clj
│ │ └── write.clj
│ ├── codecs.clj
│ ├── config
│ │ ├── parser.clj
│ │ └── util.clj
│ ├── core.clj
│ ├── inspect
│ │ └── core.clj
│ ├── platforms
│ │ ├── api.clj
│ │ ├── core.clj
│ │ └── golang
│ │ │ ├── core.clj
│ │ │ ├── system.clj
│ │ │ └── userspace.clj
│ ├── protobuf
│ │ └── generate.clj
│ ├── subcommands
│ │ ├── build.clj
│ │ ├── buildcar.clj
│ │ ├── clean.clj
│ │ ├── deps.clj
│ │ ├── env.clj
│ │ ├── inspect.clj
│ │ ├── ls.clj
│ │ ├── package.clj
│ │ ├── proto.clj
│ │ └── unpack.clj
│ └── util.clj
└── org
│ └── hyperledger
│ └── chaintool
│ └── meta
│ └── OrgHyperledgerChaintoolMeta.java
└── test
└── chaintool
├── build
└── test_interface.clj
├── platforms
└── golang
│ ├── test_core.clj
│ └── test_system.clj
└── protobuf
└── test_generate.clj
/.github/settings.yml:
--------------------------------------------------------------------------------
1 | repository:
2 | name: fabric-chaintool
3 | description: null
4 | homepage: https://wiki.hyperledger.org/display/fabric
5 | default_branch: master
6 | has_downloads: true
7 | has_issues: false
8 | has_projects: false
9 | has_wiki: false
10 | archived: true
11 | private: false
12 | allow_squash_merge: true
13 | allow_merge_commit: false
14 | allow_rebase_merge: true
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /lib
3 | /classes
4 | /checkouts
5 | pom.xml
6 | *.jar
7 | *.class
8 | .lein-deps-sum
9 | .lein-failures
10 | .lein-plugins
11 | .idea
12 | *.iml
13 | **/node_modules
14 | **/out
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## v0.10.3 February 22, 2017
2 |
3 | * [c7caae4](https://github.com/hyperledger/fabric/commit/c7caae4) Release v0.10.3
4 | * [5fde1e5](https://github.com/hyperledger/fabric/commit/5fde1e5) Link golang chaincode with -static
5 | * [cf55d6c](https://github.com/hyperledger/fabric/commit/cf55d6c) Prepare for v0.10.3 development
6 |
7 | ## v0.10.2 February 14, 2017
8 |
9 | * [b579a6a](https://github.com/hyperledger/fabric/commit/b579a6a) Release v0.10.2
10 | * [708af63](https://github.com/hyperledger/fabric/commit/708af63) Add basic support for eventhub
11 | * [62f24c2](https://github.com/hyperledger/fabric/commit/62f24c2) Remove base64 from protocol
12 | * [d2ceb4e](https://github.com/hyperledger/fabric/commit/d2ceb4e) Prepare for v0.10.2 development
13 |
14 | ## v0.10.1 February 7, 2017
15 |
16 | * [e40a745](https://github.com/hyperledger/fabric/commit/e40a745) Import release v0.10.1
17 |
18 | ## v0.10.0 February 7, 2017
19 |
20 | * [9a8948b](https://github.com/hyperledger/fabric/commit/9a8948b) Import release v0.10.0
21 |
22 | ## v0.9.2 February 7, 2017
23 |
24 | * [6d0f535](https://github.com/hyperledger/fabric/commit/6d0f535) Import release v0.9.2
25 |
26 | ## v0.9.1 February 7, 2017
27 |
28 | * [3c23654](https://github.com/hyperledger/fabric/commit/3c23654) Import release v0.9.1
29 |
30 | ## v0.9.0 February 7, 2017
31 |
32 | * [aecaced](https://github.com/hyperledger/fabric/commit/aecaced) Import release v0.9.0
33 |
34 | ## v0.8.1 February 7, 2017
35 |
36 | * [f92acb3](https://github.com/hyperledger/fabric/commit/f92acb3) Import release v0.8.1
37 |
38 | ## v0.8.0 February 7, 2017
39 |
40 | * [20eadfd](https://github.com/hyperledger/fabric/commit/20eadfd) Import release v0.8.0
41 |
42 | # Change Log
43 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
44 |
45 | ## [Unreleased][unreleased]
46 | ### Changed
47 | - Add a new arity to `make-widget-async` to provide a different widget shape.
48 |
49 | ## [0.1.1] - 2016-01-20
50 | ### Changed
51 | - Documentation on how to make the widgets.
52 |
53 | ### Removed
54 | - `make-widget-sync` - we're all async, all the time.
55 |
56 | ### Fixed
57 | - Fixed widget maker to keep working when daylight savings switches over.
58 |
59 | ## 0.1.0 - 2016-01-20
60 | ### Added
61 | - Files from the new template.
62 | - Widget maker public API - `make-widget-sync`.
63 |
64 | [unreleased]: https://github.com/your-name/obcc/compare/0.1.1...HEAD
65 | [0.1.1]: https://github.com/your-name/obcc/compare/0.1.0...0.1.1
66 |
67 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
68 | s
69 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | # Fabric Maintainers
4 | * @hyperledger/fabric-maintainers
5 |
6 | # Fabric Chaintool Maintainers
7 | * @hyperledger/fabric-chaintool-maintainers
8 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | Code of Conduct Guidelines
2 | ==========================
3 |
4 | Please review the Hyperledger [Code of
5 | Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct)
6 | before participating. It is important that we keep things civil.
7 |
8 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
9 |
--------------------------------------------------------------------------------
/MAINTAINERS.txt:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: CC-BY-4.0
5 | #
6 |
7 | Greg Haskins
8 | Eric Baur
9 | Muralidharan Srinivasan
10 |
11 | Also:
12 | https://github.com/hyperledger/fabric/blob/master/docs/source/MAINTAINERS.rst
13 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | NAME=chaintool
8 | LEIN = $(shell which lein || echo ./lein)
9 | BINDIR ?= /usr/local/bin
10 | OUTPUT=target/$(NAME)
11 | META=org.hyperledger.chaintool.meta
12 |
13 | SRCS += $(shell find src -type f)
14 | SRCS += $(shell find resources -type f)
15 |
16 | PROTOS += $(shell find resources/proto -name "*.proto")
17 | PROTOS += target/$(META).proto
18 |
19 | all: $(OUTPUT)
20 |
21 | $(OUTPUT): $(SRCS) Makefile project.clj
22 | @$(LEIN) bin
23 |
24 | $(PREFIX)$(BINDIR):
25 | mkdir -p $@
26 |
27 | # Bootstrap! We use chaintool to build a .proto for chaintool.
28 | # If HEAD will not build, an older release of chaintool may be
29 | # used to generate this file by hand
30 | target/$(META).proto: resources/metadata/$(META).cci $(OUTPUT)
31 | $(OUTPUT) proto -o $@ $<
32 |
33 | proto: $(PROTOS)
34 | protoc --java_out=./src $(PROTOS)
35 |
36 | install: $(OUTPUT) $(PREFIX)$(BINDIR)
37 | cp $(OUTPUT) $(PREFIX)$(BINDIR)
38 |
39 | clean:
40 | @echo "Cleaning up.."
41 | @$(LEIN) clean
42 | -@rm -rf target
43 | -@rm -f *~
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **Note:** Issue tracking is handled in [Jira](https://jira.hyperledger.org)
2 |
3 | ## Documentation, Getting Started and Developer Guides
4 |
5 | Please visit our [online documentation](http://fabric-chaintool.readthedocs.io/en/latest/) for information on getting started using and developing with chaintool.
6 |
7 | ## Contributing
8 |
9 | We welcome contributions to the Hyperledger Project in many forms. There’s always plenty to do!
10 | Check [the documentation on how to contribute to this project](http://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html) for the full details.
11 |
12 | ## Community
13 |
14 | [Hyperledger Community](https://www.hyperledger.org/community)
15 |
16 | [Hyperledger mailing lists and archives](http://lists.hyperledger.org/)
17 |
18 | [Hyperledger Chat](http://chat.hyperledger.org/channel/fabric-chaintool)
19 |
20 | [Hyperledger Wiki](https://wiki.hyperledger.org/)
21 |
22 | [Hyperledger Code of Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct)
23 |
24 | [Community Calendar](https://wiki.hyperledger.org/community/calendar-public-meetings)
25 |
26 | ## License
27 | The Hyperledger Project uses the [Apache License Version 2.0](LICENSE) software license.
28 |
29 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
30 |
--------------------------------------------------------------------------------
/ci/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - master
3 |
4 | pool:
5 | vmImage: 'ubuntu-latest'
6 |
7 | steps:
8 |
9 | - script: |
10 | make all
11 | displayName: 'Make everything'
--------------------------------------------------------------------------------
/dev/user.clj:
--------------------------------------------------------------------------------
1 | (ns user
2 | (:require [clojure.tools.namespace.repl :refer [refresh]]))
3 |
4 | ;; user is a namespace that the Clojure runtime looks for and loads if
5 | ;; its available
6 |
7 | ;; You can place helper functions in here. This is great for starting
8 | ;; and stopping your webserver and other development services
9 |
10 | ;; The definitions in here will be available if you run "lein repl" or launch a
11 | ;; Clojure repl some other way
12 |
13 | ;; You have to ensure that the libraries you :require are listed in the :dependencies
14 | ;; in the project.clj
15 |
16 | ;; Once you start down this path
17 | ;; you will probably want to look at
18 | ;; tools.namespace https://github.com/clojure/tools.namespace
19 | ;; and Component https://github.com/stuartsierra/component
20 |
21 | ;; or the exciting newcomer https://github.com/weavejester/integrant
22 |
23 | ;; DEVELOPMENT SERVER HELPERS: starting and stopping a development server in the REPL
24 |
--------------------------------------------------------------------------------
/docs/application-development.md:
--------------------------------------------------------------------------------
1 | # Chaincode Application Development
2 |
3 | ## Project Structure
4 |
5 | Like many modern build tools, _chaintool_ is opinionated. It expects a specific structure to your project as follows:
6 |
7 | - [chaincode.yaml](#chaincodeyaml) in the top-level directory of your project
8 | - a chaincode entry-point in ./src/chaincode ([example](https://github.com/hyperledger/fabric-chaintool/tree/master/examples/example02/app/src/chaincode))
9 | - interface files in ./src/interfaces ([example](https://github.com/hyperledger/fabric-chaintool/tree/master/examples/example02/app/src/interfaces))
10 | - every project must define an appinit interface ./src/interfaces/appinit.cci ([example](interface.md#appinit-interface))
11 |
12 | ### chaincode.yaml
13 |
14 | _chaincode.yaml_ is the central configuration file for a given chaintool-managed chaincode project. An example looks like this:
15 |
16 | ```
17 | # ----------------------------------
18 | # chaincode example02
19 | # ----------------------------------
20 | #
21 | # Copyright (C) 2016 - Hyperledger
22 | # All rights reserved
23 | #
24 |
25 | Schema: 1
26 | Name: org.hyperledger.chaincode.example02
27 | Version: 0.1-SNAPSHOT
28 |
29 | Platform:
30 | Name: org.hyperledger.chaincode.golang
31 | Version: 1
32 |
33 | Provides: [self] # 'self' is a keyword that means there should be $name.cci (e.g. org.hyperledger.chaincode.example02.cci)
34 | ```
35 |
36 | All chaincode.yaml should minimally contain:
37 |
38 | - schema
39 | - project name/version
40 | - platform
41 | - interface declarations (provides/consumes)
42 |
43 | #### Schema
44 | This helps to relay compatibility with the structures used in the chaincode.yaml itself. At the time of writing, it should be "1".
45 |
46 | #### Project name/version
47 |
48 | This is something that should uniquely identify your chaincode project for human/UX consumption. It is generally advised that a DNS name of some kind be incorporated to promote global uniqueness. Note that the Hyperledger subsystem in general does not interpret these names in any meaningful way other than for display purposes.
49 |
50 | #### Platform
51 |
52 | It is here that a chaincode may declare the compatibility/conformity to a specific platform. The idea is to promote extensibility (e.g. other platforms may be added in the future) and also compatility (e.g. platform X, version Y may mean something very specifically about the type of chaincode language supported, the ABI for any peripheral libraries, etc). It is analogous to the notion that java 1.7 is a different ABI than java 1.8, etc. At the time of writing, the only supported platform are:
53 |
54 | - [org.hyperledger.chaincode.golang](./platforms/golang.md) - The canonical platform for chaincode development, expressed as a chaintool managed superset.
55 | - [org.hyperledger.chaincode.system](./platforms/system.md) - A special variant of [org.hyperledger.chaincode.golang](./platforms/golang.md) designed for system-chaincode development as an extension of the hyperledger fabric. This platform is implicitly golang based and notably not compiled as system chaincode is compiled as part of the fabric build.
56 |
57 | More platforms may be added in the future.
58 |
59 | ##### Adding platforms
60 |
61 | The only core requirement is that both _chaintool_ and the chosen Hyperledger network are in agreement to support said platform. The details of implementing this are "coming soon".
62 |
63 | #### Interface Declarations
64 |
65 | Interfaces (as included in ./src/interfaces) may be in one or two categories: Provided or Consumed. _Provided_ means that the chaincode implements the interface and supports having clients or other chaincode invoke methods as declared. Likewise, _consumed_ indicates that the chaincode expects to perform inter-chaincode invoke operations to a disparate chaincode instance that provides the interface. It is perfectly fine (though perhaps uncommon) for a chaincode to both provide and consume a given interface (such as for proxy contracts which may accept operations in a polymorphic manner before passing operations on to a concrete instance).
66 |
67 | Both Provides and Consumes are expressed as an array of 1 or more entries. For example:
68 |
69 | ```
70 | Provides: [org.hyperledger.chaincode.example02, org.hyperledger.chaincode.example03]
71 | Consumes: [org.hyperledger.chaincode.example02]
72 | ```
73 |
74 | If there aren't any interfaces in a particular category, the entry may be omitted. Note that a chaincode that doesn't provide any interfaces doesn't sound particularly useful, however. Therefore, it is expected that every project will include at least a Provides clause.
75 |
76 | ##### "self"
77 |
78 | The keyword _self_ may be used as shorthand for an interface that shares the same name as the project (for instance, the org.hyperledger.chaincode.example02 project surfacing the org.hyperledger.chaincode.example02.cci interface), as a convenience. It is idiomatic for a project to name its primary interfaces after itself, and therefore this shortcut is expected to be commonly used. Example:
79 |
80 | ```
81 | Provides: [self]
82 | ```
83 |
84 | ### Chaincode
85 |
86 | The opinionated portion of chaincode path solely applies to the entry-point for your application. Other paths for non-entry point code are generally fine if you are using a language that supports namespaces, etc. For instance, the org.hyperledger.chaincode.golang platform assumes a $GOPATH of ./src and tries to build "chaincode" (via $GOPATH/src/chaincode). However, if your chaincode uses go imports such as:
87 |
88 | ```golang
89 | import (
90 | "foo"
91 | "bar/baz"
92 | )
93 | ```
94 |
95 | placed in ./src/foo and ./src/bar/baz respectively, they will be discovered perfectly fine.
96 |
97 |
98 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
99 | s
100 |
--------------------------------------------------------------------------------
/docs/client-development.md:
--------------------------------------------------------------------------------
1 | # Interacting With Chaintool Managed Applications
2 |
3 | ## Tooling
4 |
5 | _chaintool_ uses a protobuf-based protocol tunneled over the standard Fabric chaincode protocol. You may find that [chaintool proto](command-reference.md#chaintool-proto) and [chaintool inspect](command-reference.md#chaintool-inspect) commands are helpful to translate from [CCI](interface.md) to .proto files for your client's consumption.
6 |
7 | ## Protocol
8 |
9 | ### Input Protocol
10 |
11 | The standard Fabric protocol consists of an array of byte "args". This protobuf schema for the standard chaincode protocol is:
12 | ```
13 | message ChaincodeInput {
14 |
15 | repeated byte args = 1;
16 |
17 | }
18 | ```
19 | Chaintool deterministically maps functions declared within a CCI to an [encoded function name](#function-encoding), and expects the corresponding input parameter to be a serialized protobuf message as the first and only arg string.
20 |
21 | Example:
22 | ```
23 | ["org.hyperledger.chaincode.example02/fcn/3","CgNmb28="]
24 | ```
25 |
26 | #### Function Encoding
27 |
28 | Function naming follows the convention *interface-name/fcn/method-index*. For instance, invoking *MakePayment* from our [example](https://github.com/hyperledger/fabric-chaintool/tree/master/examples/example02) would be *org.hyperledger.chaintool.example02/fcn/1*. Because its function #1 in the org.hyperledger.chaintool.example02 interface.
29 |
30 | ### Output Protocol
31 |
32 | Standard chaincode protocol allows chaincode applications to return a byte-array payload to a caller. Chaintool managed applications will encode this payload with a serialized protobuf structure (when applicable).
33 |
34 | ### Protobuf "hints"
35 |
36 | The .proto file generated from *chaintool* (such as *chaintool proto*) contains hints to help developers understand the protocol. For instance, see the comments at the bottom of this .proto generated from example02:
37 |
38 | ```
39 | //
40 | // Generated by chaintool. DO NOT EDIT!!
41 | //
42 |
43 | syntax = "proto3";
44 |
45 | package org.hyperledger.chaincode.example02;
46 |
47 | message BalanceResult {
48 | int32 balance = 1;
49 | }
50 |
51 | message Entity {
52 | string id = 1;
53 | }
54 |
55 | message PaymentParams {
56 | string partySrc = 1;
57 | string partyDst = 2;
58 | int32 amount = 3;
59 | }
60 |
61 | //
62 | // Available RPC functions exported by this interface
63 | //
64 | // void MakePayment(PaymentParams) -> org.hyperledger.chaincode.example02/fcn/1
65 | // void DeleteAccount(Entity) -> org.hyperledger.chaincode.example02/fcn/2
66 | // BalanceResult CheckBalance(Entity) -> org.hyperledger.chaincode.example02/fcn/3
67 | ```
68 |
69 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
70 | s
71 |
--------------------------------------------------------------------------------
/docs/command-reference.md:
--------------------------------------------------------------------------------
1 | # Command Reference
2 |
3 | #### chaintool build
4 |
5 | Builds your chaincode project into a executable. When used locally, _chaintool build_ allows a developer to verify that their project compiles without errors or warnings before deployment. Validating peers also each use _chaintool build_ to prepare a chaincode archive for execution on the actual blockchain. Developers achieve fidelity in chaincode development workflows because they have access to the same build environment that will eventually be used when their application is deployed.
6 |
7 | Various artifacts are emitted to ./build, depending on the platform. For [org.hyperledger.chaincode.golang](./platforms/golang.md):
8 |
9 | - ./build/src: stub, protobufs, etc
10 | - ./build/deps: direct and transitive dependencies of your chaincode, as retrieved by "go get". NOTE: this option is likely to default to disabled in the future, since it is not a good idea for a validating peer to be pulling dependencies down. Rather, there should be some fixed number of dependencies that are implicitly included with the platform. For now, we pull things in dynamically.
11 | - ./build/bin: the default location for the binary generated (override with -o)
12 |
13 | #### chaintool clean
14 |
15 | Cleans a chaincode project. This typically translates to removing the ./build directory, but platforms are free to define this as they see fit and may perform additional or alternative operations.
16 |
17 | #### chaintool package
18 |
19 | Packages the sourcecode, interfaces, chaincode.yaml, and other project data into a .car file suitable for deployment. Note that any artifacts generated by commands such as _build_ and _buildcar_ are _not_ included but rather will be rebuilt locally by each validating peer in the network.
20 |
21 | #### chaintool ls
22 |
23 | Displays the contents of an existing .car file.
24 | ```
25 | $ chaintool ls ./build/org.hyperledger.chaincode.example02-0.1-SNAPSHOT.car
26 | |------+------------------------------------------+--------------------------------------------------------|
27 | | Size | SHA1 | Path |
28 | |------+------------------------------------------+--------------------------------------------------------|
29 | | 438 | d28b22c7c30506af926dcb5bc8b946ac35ddac7f | chaincode.yaml |
30 | | 3856 | 542d088197e1a46bc21326e67e5d84d2d2807283 | src/chaincode/chaincode_example02.go |
31 | | 143 | 7305f65e18e4aab860b201d40916bb7adf97544f | src/interfaces/appinit.cci |
32 | | 375 | 9492a1e96f380a97bba1f16f085fc70140154c65 | src/interfaces/org.hyperledger.chaincode.example02.cci |
33 | |------+------------------------------------------+--------------------------------------------------------|
34 | Platform: org.hyperledger.chaincode.golang version 1
35 | Digital Signature: none
36 | Raw Data Size: 4812 bytes
37 | Archive Size: 2371 bytes
38 | Compression Alg: gzip
39 | Chaincode SHA3: f7026e0675b22a9d78b9f7f0cb97c93165bdefedc86de97f00e76b506c707b4ddbdfe97ad702ad600eae518891b9f0f1c8cb9a8b29b83908c2f6d46a6bcf4ecd
40 | ```
41 |
42 | #### chaintool unpack
43 |
44 | Unpacks a .car archive into the filesystem as a chaincode project.
45 |
46 | #### chaintool buildcar
47 |
48 | Combines _unpack_ with _build_ by utilizing a temporary directory. This allows a project to be built from a .car file without explicitly unpacking it first, as a convenience.
49 |
50 | #### chaintool proto
51 |
52 | Compiles a .cci file into a .proto file, suitable for developing clients using standard protobuf-based tooling.
53 |
54 | #### chaintool inspect
55 |
56 | Retrieves [metadata](./metadata.md) from a running instance, optionally saving the interface definitions to a local directory.
57 |
58 | ```
59 | $ chaintool inspect -n mycc
60 | Connecting to http://localhost:3000/chaincode
61 | |---------------------+--------------------------------------------|
62 | | Fact | Value |
63 | |---------------------+--------------------------------------------|
64 | | Application Name | org.hyperledger.chaincode.example02 |
65 | | Application Version | 0.1-SNAPSHOT |
66 | | Platform | org.hyperledger.chaincode.golang version 1 |
67 | | Chaintool Version | 0.7 |
68 | |---------------------+--------------------------------------------|
69 | Exported Interfaces:
70 | - appinit
71 | - org.hyperledger.chaincode.example02
72 |
73 | ```
74 |
75 |
76 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
77 | s
78 |
--------------------------------------------------------------------------------
/docs/getting-started.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | ## Installation
4 |
5 | ### Prerequisites
6 | - [Java](https://www.java.com) JRE/JDK v1.8 (or higher)
7 | - [Golang](https://golang.org) v1.7 or higher
8 | - [Protobuf Compiler](https://developers.google.com/protocol-buffers/docs/downloads) v3.0 or higher
9 | - [protoc-gen-go](https://github.com/golang/protobuf/tree/master/protoc-gen-go)
10 |
11 | ### Install
12 | Download the latest [release](https://github.com/hyperledger/fabric-chaintool/releases) and install it in your $PATH
13 |
14 | #### Example
15 | ```
16 | $ sudo curl https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric/chaintool-1.0.0/hyperledger-fabric-chaintool-1.0.0.jar -Lo /usr/local/bin/chaintool && sudo chmod +x /usr/local/bin/chaintool
17 | ```
18 |
19 | ### Usage
20 | Chaintool supports a number of "actions" (e.g. "chaintool build"). See _chaintool -h_ for details.
21 |
22 | ```
23 | $ chaintool -h
24 | chaintool version: v1.0.0
25 |
26 | Usage: chaintool [general-options] action [action-options]
27 |
28 | General Options:
29 | -v, --version Print the version and exit
30 | -h, --help
31 |
32 | Actions:
33 | build -> Build the chaincode project
34 | buildcar -> Build the chaincode project from a CAR file
35 | clean -> Clean the chaincode project
36 | package -> Package the chaincode into a CAR file for deployment
37 | unpack -> Unpackage a CAR file
38 | ls -> List the contents of a CAR file
39 | proto -> Compiles a CCI file to a .proto
40 | inspect -> Retrieves metadata from a running instance
41 |
42 | (run "chaintool -h" for action specific help)
43 | ```
44 |
45 | ## Development Overview
46 | Every chaintool based chaincode application minimally consists of the chaincode itself, and one or more clients to communicate with it. For our walk-through, we will be using the standard [golang-based](platforms/golang.md#golang-chaincode-platform) chaincode model, version 1, and the [Node SDK](https://www.npmjs.com/package/fabric-client).
47 |
48 | It is assumed that the reader is familiar with Hyperledger Fabric in general, and [how to develop](http://hyperledger-fabric.readthedocs.io/en/latest/chaincode.html) "standard" (i.e. non-chaintool based) chaincode and clients.
49 |
50 | ### Phase 1: Chaincode Development
51 | We will begin by defining our chaincode application, since this will dictate the operations that a client needs to support.
52 |
53 | - Create a directory to hold your chaincode application logic.
54 | - We will refer to this directory as $CHAINCODE in the remainder of this document.
55 | - Optional: Set up an SCM such as git.
56 | - Define your [interfaces](interface.md) under $CHAINCODE/src/interfaces
57 | - [$CHAINCODE/src/interfaces/appinit.cci](interface.md#appinit-interface): This defines the "constructor" arguments for your application.
58 | - Create one or more application specific interfaces: These define the general methods and arguments for your application.
59 | - E.g. $CHAINCODE/src/interfaces/org.acme.myapplication.cci
60 | - Tip: Use reverse DNS naming to ensure your interface is globally unique.
61 | - Define your [$CHAINCODE/chaincode.yaml](application-development.md#chaincodeyaml) project definition.
62 | - Set [schema v1](application-development.md#schema)
63 | - Set your project [name and version](application-development.md#project-nameversion)
64 | - Use platform specifier [org.hyperledger.chaincode.golang v1](platforms/golang.md#platform-specifier)
65 | - Be sure to update the [interface declarations](application-development#interface-declarations) (i.e. _Provides_ and _Consumes_) with the CCI files added in the previous step.
66 | - Define your [chaincode entrypoint](platforms/golang.md#entry-point) under $CHAINCODE/src/chaincode.
67 | - E.g. $CHAINCODE/src/chaincode/main.go
68 | - [Import](platforms/golang.md#imports) the chaintool generated code and fabric shim.
69 | - [Register](platforms/golang.md#hooks-and-registration) your chaincode inside your main() function.
70 | - Write your application logic by [implementing](platforms/golang.md#callbacks) your interfaces.
71 | - Init() for appinit.cci
72 | - Any other functions declared within interfaces specified as _Provided_ in your chaincode.yaml
73 |
74 | Note: You may find a complete chaincode example [here](https://github.com/hyperledger/fabric-chaintool/tree/master/examples/example02/app)
75 |
76 | You man run _chaintool build_ at this time to locally verify compilation of your application. However, before you may deploy it to a Fabric network, you will need to develop a client for your application using one of the Fabric SDKs. Proceed to Phase 2.
77 |
78 | ### Phase 2: Client Development
79 | Chaintool-based chaincodes employ a specific [parameter encoding](client-development.md#protocol) based on [Google Protocol Buffers (protobufs)](https://developers.google.com/protocol-buffers/). Because of this encoding, chaintool-based chaincodes are not generally compatible with the _peer CLI_ methods. Rather, we must develop a client in code that is capable of performing the encoding/decoding for us.
80 |
81 | Fortunately Fabric provides a variety of SDKs on platforms that also enjoy robust protobuf support. Therefore, one only needs to build a standard client on the platform of the reader's choosing, with the additional understanding of the chaintool imposed parameter encoding scheme.
82 |
83 | We will be building a client using the [Node SDK](https://www.npmjs.com/package/fabric-client). It is beyond the scope of this document to cover basic Node SDK client development. Instead, we will focus solely on the elements that are specific to chaintool.
84 |
85 | #### Encoding Details
86 | ##### Input Parameter Encoding
87 | Consider the following CCI snippet taken from _org.hyperledger.chaincode.example02.cci_:
88 | ```
89 | message PaymentParams {
90 | string partySrc = 1;
91 | string partyDst = 2;
92 | int32 amount = 3;
93 | }
94 |
95 | ...
96 |
97 | functions {
98 | void MakePayment(PaymentParams) = 1;
99 | ...
100 | }
101 | ```
102 |
103 | A client wishing to invoke MakePayment() would encode the request into an input array via the SDK as follows:
104 |
105 | ```
106 | ["org.hyperledger.chaincode.example02/fcn/1", "CgNmb28="]
107 | ```
108 |
109 | Where "org.hyperledger.chaincode.example02" is the name of the interface we are invoking, "fcn" is a constant, "1" is the index of the "MakePayment" method, and _ "CgNmb28="_ is a protobuf encoding of _PaymentParams_.
110 |
111 | ##### Output Parameter Encoding
112 | For methods that return non-void types, the output will be a protobuf encoded byte array.
113 |
114 | #### Integrating with the Node SDK
115 |
116 | As mentioned above, a client for a chaintool-based application is virtually identical to a non-chaintool application in all aspects except for the parameter encoding. In order to add support for the requisite encoding, we need three basic things:
117 |
118 | - One or more .proto files representing the protobuf schema we want to use as the basis of encode/decode.
119 | - TIP: _chaintool proto_ can convert a CCI file to a pure .proto file for convenient client consumption.
120 | - A NodeJS compatible protobuf library that can work with our .proto schemas.
121 | - [protobuf.js](https://www.npmjs.com/package/protobufjs) is an excellent choice. It can work using just your .proto files and reflection, eliminating a discrete protoc compilation phase found in many other platforms.
122 | - The integration of the two items above together to encode/decode our input and output parameters properly.
123 |
124 | For the Node SDK, this can be as simple as defining a request object such as:
125 | ```
126 | var args = new app.PaymentParams({'partySrc':'A', 'partyDst':'B', 'amount':100});
127 | var request = {
128 | chaincodeType: 'car',
129 | fcn: 'org.hyperledger.chaincode.example02/fcn/1',
130 | args: [args.toBuffer()]
131 | };
132 | ```
133 |
134 | A complete example client can be found [here](https://github.com/hyperledger/fabric-chaintool/tree/master/examples/example02/client/nodejs)
135 |
136 | ### Phase 3: Deployment
137 | Generally speaking, deployment of chaincode in Fabric involves two discrete steps: _Install_ and _Instantiate_. The Install phase is where a chaincode application is provided to the network. The Instantiate phase is where a previously installed application is initialized and enters an active state in the network.
138 |
139 | Chaintool-based chaincode is not materially different in this overall flow. What is different is the packaging and encodings that are used.
140 |
141 | #### Packaging
142 | Chaintool provides a package format called CAR (Chaincode Archive). This format was designed from the ground up to be a deterministic and platform agnostic way to package up chaincodes for Fabric.
143 |
144 | - Run _chaintool package_ to create a Fabric deployment package from your project.
145 | - Use _chaintool ls_ or _chaintool unpack_ to work with CAR files previously generated.
146 |
147 | #### Installation
148 | Both the _peer CLI_ and _Node SDK_ have native support for installing CAR packages. Since there are no parameter encodings that accompany _install_, you may chose the workflow that best suits you.
149 |
150 | #### Instantiation
151 | Instantiating a previously installed CAR file involves encoding the Init() parameters (as designed in your application's appinit.cci). Therefore, it is most convenient to use the SDK's _chain.sendInstantiateProposal()_ for this operation. Simply encode the appinit.cc::Init{} message in the request.fcn/request.args as previously noted.
152 |
153 | ### Phase 4: Interacting with your service
154 | At this phase, your chaincode application is up and running. You may execute Invoke() and Query() operations against it just like any other chaincode, as long as you adhere to the encoding schemas.
155 |
156 | Congratulations!
157 |
158 | ### Questions/Comments?
159 | Join us on the #fabric-chaintool channel on [Hyperledger Rocket Chat](https://chat.hyperledger.org) or reach out to us on the [hyperledger-fabric mailing list](https://lists.hyperledger.org/mailman/listinfo/hyperledger-fabric).
160 |
161 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
162 | s
163 |
--------------------------------------------------------------------------------
/docs/images/typical-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperledger-archives/fabric-chaintool/57d8f460d0bfdc7cb4ddea0147fea16f15a06258/docs/images/typical-workflow.png
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Introduction to Chaintool - A Hyperledger Fabric Chaincode Compiler
2 |
3 | ## Summary
4 |
5 | _chaintool_ is a utility to assist in various phases of [Hyperledger Fabric](https://github.com/hyperledger/fabric) chaincode development, such as compilation, test, packaging, and deployment. A chaincode app developer may express the interface to their application in a highlevel interface definition language, and _chaintool_ will generate (1) chaincode stubs and (2) package the chaincode for convenient deployment.
6 |
7 | This provides the following benefits to chaincode development:
8 |
9 | - a language neutral description of the application interface
10 | - a language neutral packaging of chaincode for deployment
11 | - on the wire endian neutrality
12 | - built-in field validation
13 | - forwards/backwards compatiblity management
14 | - stub function dispatch
15 | - build/package management
16 | - a unified query, signing, hashing, and introspection interface
17 |
18 | ## Overview
19 |
20 | Working with _chaintool_ generally involves structuring your chaincode [project root](./application-development.md#project-structure) a specific way and then running various [subcommands](./command-reference.md). Some commands, such as _build_, _clean_, and _package_, are used to manage general development activities. These commands expect to be executed from within your project root by default, but may also be executed from anywhere using the "-p" switch.
21 |
22 | Other commands such as _buildcar_, _unpack_, and _ls_ are designed to operate against a Chaincode Archive (CAR) from a previous _package_ operation. These commands expect a path to a CAR file.
23 |
24 | In all cases, you may obtain subcommand specific help by invoking "chaintool _$subcommand_ -h". For example:
25 |
26 | ```
27 | $ chaintool package -h
28 | chaintool version: v0.10.1
29 |
30 | Description: chaintool package - Package the chaincode into a CAR file for deployment
31 |
32 | Usage: chaintool package [options]
33 |
34 | Command Options:
35 | -o, --output NAME path to the output destination
36 | -c, --compress NAME gzip compression algorithm to use
37 | -p, --path PATH ./ path to chaincode project
38 | -h, --help
39 | ```
40 |
41 | ### Typical Workflow
42 |
43 | 
44 |
45 |
46 |
47 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
48 | s
49 |
--------------------------------------------------------------------------------
/docs/interface.md:
--------------------------------------------------------------------------------
1 | # Interface Definition Language
2 |
3 | An interface is a file ending in .cci (Chaincode Interface) that defines a language neutral definition for various RPC-like functions that a given chaincode instance supports. An chaincode instance may in fact support many different interfaces at one time. This is convenient for creating a type of polymorphism within a network of chaincode instances.
4 |
5 | Each .cci file is meant to represent an interface contract for compatibility. Items declared within a .cci file have provisions (similar to protobuf indices) for mutating structures over time that do not break forwards or backwards compatibility. Changes to a given interface should only be done in a manner which exploits this compatibility mechanism. If for some reason it is mandated that compatibility _must_ be broken, the name of the interface should be changed.
6 |
7 | ## Interface names
8 |
9 | The name of the .cci file has direct meaning to the ABI: the name of the file will be translated into ABI tokens on the wire. This was intentionally chosen so that the filesystem itself (under ./src/interfaces) takes a role in ensuring that only one interface of a particular type is in use within a project at any given time. Likewise, if a project wishes to import and consume an interface from a different project, it is imperative that the filename be retained across both projects or the endpoints will be inadvertently namespace-isolated from one another. To put it another way, do not rename .cci files on import!
10 |
11 | Perhaps even more importantly, interface ABI needs to be globally managed. Therefore it is advised to name .cci files in a way that is globally unique. A UUID would suffice, at the expense of being somewhat difficult to humans to deal with. Therefore, it is advised to name interfaces using DNS names as in the examples provided here.
12 |
13 | ## Definition
14 |
15 | Each interface definition loosely adheres to a protobuf-ish syntax. This was intentional, as the .cci file is actually translated into an intermediate .proto file before being handed to protoc to do the real work. The reason we did not just use protobuf syntax directly was because it was felt there were a few areas of the protobuf grammar that were suboptimal w.r.t. chaincode definition. Consider an example .cci:
16 |
17 | ```
18 | message PaymentParams {
19 | string partySrc = 1;
20 | string partyDst = 2;
21 | int32 amount = 3;
22 | }
23 |
24 | message Entity {
25 | string id = 1;
26 | }
27 |
28 | message BalanceResult {
29 | int32 balance = 1;
30 | }
31 |
32 | functions {
33 | void MakePayment(PaymentParams) = 1;
34 | void DeleteAccount(Entity) = 2;
35 | BalanceResult CheckBalance(Entity) = 3;
36 | }
37 | ```
38 |
39 | The _message_ definitions are almost 1:1 with protobuf grammar. The largest divergence is w.r.t. the _functions_ section. This section is similiar to the notion of service/rpc in protobuf grammar. We diverged from the protobuf/grpc grammar because it was felt that the lack of "field indices" was a large shortcoming in ABI compatibility. Therefore, the grammar used here retains the notion of indices even for function calls.
40 |
41 | The main purpose of the grammar is to define RPC functions. For reasons of ABI stability, it was decided that all RPCs will have the following properties:
42 | - Be indexed (e.g. ABI depends on index stability, not function name)
43 | - Accept only 0 or 1 _message_ as input and return only 0 (via _void_) or 1 message as output
44 | - We rely on the message definitions for further ABI stability.
45 |
46 | ## "Appinit" interface
47 |
48 | Every project has an implicit interface: appinit.cci. This interface is intended to define the "init" or constructor function for a given chaincode. It is also generally assumed to be not something that needs to be shared with other projects in the same manner that application-level interfaces might, thus we are not concerned about "appinit.cci" name conflicting in the way we care about other interfaces.
49 |
50 | The interface expected to define a message "Init" with no RPCs. This message will be assumed to be the argument to the chaincode constructor.
51 |
52 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
53 | s
54 |
--------------------------------------------------------------------------------
/docs/metadata.md:
--------------------------------------------------------------------------------
1 | ## Metadata
2 |
3 | Every chaincode application built with chaintool includes metadata which may be queried with _chaintool inspect_. This metadata contains various details about a running application, such as enumerating the interfaces surfaced by the endpoint. The caller may optionally request to download the CCI schemas for these interfaces to facilitate application-specific client interaction.
4 |
5 | ### Details
6 |
7 | Chaintool emits a shadow interface _org.hyperledger.chaintool.meta_ that supports meta queries in every application built with chaintool. This interface has the following CCI at the time of writing:
8 | ```
9 | message InterfaceDescriptor {
10 | string name = 1;
11 | bytes data = 2;
12 | }
13 |
14 | message Interfaces {
15 | repeated InterfaceDescriptor descriptors = 1;
16 | }
17 |
18 | message GetInterfacesParams {
19 | bool IncludeContent = 1;
20 | }
21 |
22 | message GetInterfaceParams {
23 | string name = 1;
24 | }
25 |
26 | message GetFactsParams {
27 | }
28 |
29 | message Facts {
30 | message Fact {
31 | string name = 1;
32 | string value = 2;
33 | }
34 |
35 | repeated Fact facts = 1;
36 | }
37 |
38 | functions {
39 | Interfaces GetInterfaces(GetInterfacesParams) = 1;
40 | InterfaceDescriptor GetInterface(GetInterfaceParams) = 2;
41 | Facts GetFacts(GetFactsParams) = 3;
42 | }
43 | ```
44 | This means that clients may optionally interact with this CCI using the same protocol discussed above to learn further details about the running application. This includes obtaining the CCI specifications of the application which may be consumed in other projects. Alternatively, users may simply use the _chaintool inspect_ command to obtain the desired information.
45 |
46 |
47 |
48 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
49 | s
50 |
--------------------------------------------------------------------------------
/docs/platforms/golang.md:
--------------------------------------------------------------------------------
1 | # Golang Chaincode Platform
2 | _Chaintool_ provides support for chaincode written in the [Go](https://golang.org/) language. This document describes the conventions of the chaintool Golang environment required for understanding and working with chaincode on this platform. It is assumed that the reader is already familar with the general usage of chaintool as well as general Golang platform within Hyperledger Fabric.
3 |
4 | ## Platform specifier
5 | Users enable the golang platform with the following configuration in chaincode.yaml:
6 | ```
7 | Platform:
8 | Name: org.hyperledger.chaincode.golang
9 | Version: 1
10 | ```
11 |
12 | ## Environment
13 | Any invocation of 'chaintool build*' will automatically synthesize the correct value for the $GOPATH environment variable based on the current value of the variable and the path of your chaincode project tree. Your chaincode project tree need _not_ be located within the directory hierarchy defined by the current value of $GOPATH. The 'chaintool build' command will ensures that the build correctly includes Go code from following paths (where $CHAINCODE is the root directory of your application chaincode.)
14 |
15 | - $CHAINCODE/build/deps
16 | - Direct and transitive dependencies of your application as retrieved by _go get_. (Please note: it is highly unlikely that production Hyperledger peers will use _go get_ to resolve dependencies. This use of _go get_ is an artifact of ongoing Hyperledger development; reducing development friction as the platform dependencies are refined. Operationally all dependencies will be explicit.
17 | - $CHAINCODE/build
18 | - Root directory of the default location for compiler generated artifacts.
19 | - $CHAINCODE
20 | - Root directory for your application source files. Typically all application code is stored under $CHAINCODE/src/chaincode.
21 | - current $GOPATH as set in the environment.
22 |
23 | ## Chaincode Integration
24 | ### Entry-point
25 | Your chaincode entry-point _func main()_ should be placed in a file stored in a directory under $CHAINCODE/src/chaincode/. The function should be part of a package called "chaincode". Other packages may be placed in files stored in other locations in the $CHAINCODE directory hierarchy and may be imported by your entry-point module using standard golang mechanisms. (The typical Go convention is to place source files in directories rooted at $CHAINCODE/src). Any Go files that are stored under $CHAINCODE/src will be included in the final CAR package.
26 |
27 | ### Imports
28 | In addition to any packages imported as part of your application logic your chaincode will import packages from four other locations.
29 |
30 | * hyperledger/ccs - "chaincode support"
31 | - generated "stub" code produced by the chaintool compiler
32 | * hyperledger/cci/... - "chaincode interface"
33 | - Go code which implements the interfaces defined in the application's .cci files including the required appinit.cci. The functions are placed in a package the name of which is generated from the name of the .cci file. The path to these files is likewise generated from the name of the .cci file. For example code generated from a file named "com.foo.bar.cci" is placed in the package "bar" under the path $CHAINCODE/src/hyperledger/cci/com/foo/bar
34 | * github.com/golang/protobuf/proto - google protocol buffer support
35 | - Go implementation of Google Protocol Buffers. Protocol Buffers are used by the chaintool generated code to encode messages used by chaincode.
36 | * github.com/hyperledger/fabric/core/chaincode/shim - generic Hyperledger chaincode support
37 | - Common Go language support for required chaincode operations.
38 |
39 | Here's the import section required for the 'example02' sample chaincode. This application includes "org.hyperledger.chaincode.example02.cci" and "project.cci" located in $CHAINCODE/src/interfaces/.
40 |
41 | ```
42 | import (
43 | "hyperledger/ccs"
44 | "hyperledger/cci/appinit"
45 | "hyperledger/cci/org/hyperledger/chaincode/example02"
46 |
47 | "github.com/golang/protobuf/proto"
48 | "github.com/hyperledger/fabric/core/chaincode/shim"
49 | )
50 | ```
51 |
52 | ### Hooks and Registration
53 | Each chaincode application must call ccs.Start() to register itself as chaincode with the peer. The ccs.Start() function takes a map of interface names to interface implementations expressed as pointers compatible with the CCInterface specification. This interface is generated by the compiler and placed within the interface specific stub (e.g. $CHAINCODE/build/src/hyperledger/cci/appinit/server-stub.go) . It is the application programmer's responsibility to provide an implementation for each interface declared as provided in the chaincode.yaml, plus the implicit appinit.cci.
54 |
55 | It is idiomatic to create one implementation structure (e.g. "ChaincodeExample", as shown below) to handle all interfaces. However, for special circumstances such as function-name collisions between interfaces, the caller may wish to dispatch certain interfaces to different handlers.
56 | ```
57 | type ChaincodeExample struct {
58 | }
59 |
60 | ...
61 |
62 | func main() {
63 | self := &ChaincodeExample{}
64 |
65 | // Our one instance implements both Transactions and Queries functions for all interfaces
66 | interfaces := ccs.Interfaces {
67 | "org.hyperledger.chaincode.example02": self,
68 | "appinit": self,
69 | }
70 |
71 | err := ccs.Start(interfaces)
72 | if err != nil {
73 | fmt.Printf("Error starting example chaincode: %s", err)
74 | }
75 | }
76 | ```
77 |
78 | ### Callbacks
79 |
80 | For each interface declared in the _provided_ section of the application configuration the application programmer must provide implementations for all the functions specified in the respective _transactions_ or _queries_ declarations. There is generally a 1:1 mapping between the CCI declaration and the required function signature in your code. For instance, the following CCI declaration:
81 | ```
82 | queries {
83 | BalanceResult CheckBalance(Entity) = 1;
84 | }
85 | ```
86 | requires a function signature that looks like:
87 | ```
88 | func (t *ChaincodeExample) CheckBalance(stub shim.ChaincodeStubInterface, param *example02.Entity) (*example02.BalanceResult, error) {}
89 | ```
90 | Every callback requires a shim.ChaincodeStubInterface as its first parameter, followed by an input parameter and return parameter as declared in the interface definition. Functions that return _void_ simply return a single _error_ rather than _(type, error)_.
91 |
92 | ## Generated Code File Structure
93 |
94 | ### Overview
95 |
96 | All generated code is placed in directories rooted at $CHAINCODE/build which, as mentioned earlier, is implicitly included in the $GOPATH. Interfaces are emitted to $CHAINCODE/build/src/hyperledger/cci/..., and general chaincode support stubs are emitted to $CHAINCODE/build/src/hyperledger/ccs.
97 | ```
98 | build/src/
99 | └── hyperledger
100 | ├── cci
101 | │ ├── appinit
102 | │ │ ├── interface.pb.go
103 | │ │ ├── interface.proto
104 | │ │ └── server-stub.go
105 | │ └── org
106 | │ └── hyperledger
107 | │ ├── chaincode
108 | │ │ └── example02
109 | │ │ ├── interface.pb.go
110 | │ │ ├── interface.proto
111 | │ │ └── server-stub.go
112 | │ └── chaintool
113 | │ └── meta
114 | │ ├── interface.pb.go
115 | │ ├── interface.proto
116 | │ └── server-stub.go
117 | └── ccs
118 | ├── api
119 | │ └── api.go
120 | ├── entrypoint.go
121 | └── metadata.go
122 | ```
123 | ### Interfaces
124 | The chaintool compiler generates up to four artifact types per declared interface:
125 |
126 | * interface.proto - The google protobuf definition derived from the corresponding .cci definition.
127 | * interface.pb.go - The compiled protobuf definition, as emitted by _protoc --go_out_.
128 | * server-stub.go - The server-side stub for a provided interface.
129 | * client-stub.go - The client-side stub for a consumed interface.
130 |
131 |
132 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
133 | s
134 |
--------------------------------------------------------------------------------
/docs/platforms/system.md:
--------------------------------------------------------------------------------
1 | # System Chaincode Platform
2 |
3 | System chaincode is a special variant of [org.hyperledger.chaincode.golang](golang.md) designed for system-chaincode development as an extension of the hyperledger fabric. This platform is implicitly golang based and notably not compiled as system chaincode is compiled as part of the fabric build.
4 |
5 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
6 | s
7 |
--------------------------------------------------------------------------------
/examples/example02/README.md:
--------------------------------------------------------------------------------
1 | # Example02
2 | ## Introduction
3 | This directory contains an implementation of the chaincode application called "example02" as found in the hyperledger fabric distribution. The application has been ported to chaintool to demonstrate the features, capabilities, and techniques for working with chaintool based development.
4 | ## Directory Layout
5 | ```
6 | ├── README.md
7 | ├── app
8 | │ ├── app.iml
9 | │ ├── chaincode.yaml
10 | │ └── src
11 | │ ├── chaincode
12 | │ │ └── chaincode_example02.go
13 | │ └── interfaces
14 | │ ├── appinit.cci
15 | │ └── org.hyperledger.chaincode.example02.cci
16 | └── client
17 | ├── cljs
18 | │ ├── Makefile
19 | │ ├── appinit.proto
20 | │ ├── org.hyperledger.chaincode.example02.proto
21 | │ ├── project.clj
22 | │ └── src
23 | │ └── example02
24 | │ ├── core.cljs
25 | │ ├── hlc
26 | │ │ ├── core.cljs
27 | │ │ └── user.cljs
28 | │ ├── main.cljs
29 | │ ├── rpc.cljs
30 | │ └── util.cljs
31 | └── nodejs
32 | ├── appinit.proto
33 | ├── index.js
34 | ├── util.js
35 | ├── org.hyperledger.chaincode.example02.proto
36 | └── package.json
37 | ```
38 | * app - contains a org.hyperledger.chaincode.golang platform based chaincode application.
39 | * This is the code deployed to the blockchain
40 | * client - client applications for interacting with the chaincode application
41 | * nodejs - A simple demonstration of using nodejs.
42 | * cljs - A complete client for example02 written in ClojureScript
43 |
44 | ## Deploying and interacting with the example02
45 | ### Step 1 - Fabric environment
46 | You will need a functioning peer that has chaintool v0.10.1 or higher available in the $PATH. You may check the version of chaintool you have with 'chaintool -h'. Once confirmed, start the peer with _peer node start_ as you normally would. It is advised to keep the configuration as simple as possible (1 VP, no security, noops consensus)
47 |
48 | ### Step 2 - Package the chaincode application
49 | Run 'chaintool package' from the app folder, noting the CAR output path
50 | ```
51 | $ cd app
52 | $ chaintool package
53 | Writing CAR to: /Users/ghaskins/sandbox/git/chaintool/examples/example02/app/build/org.hyperledger.chaincode.example02-0.1-SNAPSHOT.car
54 | Using path ./ ["src" "chaincode.yaml"]
55 | |------+------------------------------------------+--------------------------------------------------------|
56 | | Size | SHA1 | Path |
57 | |------+------------------------------------------+--------------------------------------------------------|
58 | | 438 | d28b22c7c30506af926dcb5bc8b946ac35ddac7f | chaincode.yaml |
59 | | 3856 | 542d088197e1a46bc21326e67e5d84d2d2807283 | src/chaincode/chaincode_example02.go |
60 | | 143 | 7305f65e18e4aab860b201d40916bb7adf97544f | src/interfaces/appinit.cci |
61 | | 375 | 9492a1e96f380a97bba1f16f085fc70140154c65 | src/interfaces/org.hyperledger.chaincode.example02.cci |
62 | |------+------------------------------------------+--------------------------------------------------------|
63 | Platform: org.hyperledger.chaincode.golang version 1
64 | Digital Signature: none
65 | Raw Data Size: 4812 bytes
66 | Archive Size: 2371 bytes
67 | Compression Alg: gzip
68 | Chaincode SHA3: f7026e0675b22a9d78b9f7f0cb97c93165bdefedc86de97f00e76b506c707b4ddbdfe97ad702ad600eae518891b9f0f1c8cb9a8b29b83908c2f6d46a6bcf4ecd
69 | ```
70 | #### Note:
71 | The _chaintool package_ command is designed to package for deployment, not development. If you started your node with _peer node start --peer-chaincodedev_, run _chaintool build_ instead. This is analogous to building non-chaintool chaincode using _go build_. The output will be placed in the _app/build/bin/_ directory.
72 | ### Step 3 - Compile the client
73 | Run 'make' from the client/cljs folder
74 | ```
75 | $ make
76 | lein npm install
77 | example02@0.1.0-SNAPSHOT /Users/ghaskins/sandbox/git/chaintool/examples/example02/client/cljs
78 | ├─┬ protobufjs@5.0.1
79 | │ ├─┬ ascli@1.0.0
80 | │ │ ├── colour@0.7.1
81 | │ │ └── optjs@3.2.2
82 | │ ├─┬ bytebuffer@5.0.1
83 | │ │ └── long@3.1.0
84 | │ ├─┬ glob@5.0.15
85 | │ │ ├─┬ inflight@1.0.4
86 | │ │ │ └── wrappy@1.0.1
87 | │ │ ├── inherits@2.0.1
88 | │ │ ├─┬ minimatch@3.0.0
89 | │ │ │ └─┬ brace-expansion@1.1.4
90 | │ │ │ ├── balanced-match@0.4.1
91 | │ │ │ └── concat-map@0.0.1
92 | │ │ ├── once@1.3.3
93 | │ │ └── path-is-absolute@1.0.0
94 | │ └─┬ yargs@3.32.0
95 | │ ├── camelcase@2.1.1
96 | │ ├─┬ cliui@3.2.0
97 | │ │ ├─┬ strip-ansi@3.0.1
98 | │ │ │ └── ansi-regex@2.0.0
99 | │ │ └── wrap-ansi@2.0.0
100 | │ ├── decamelize@1.2.0
101 | │ ├─┬ os-locale@1.4.0
102 | │ │ └─┬ lcid@1.0.0
103 | │ │ └── invert-kv@1.0.0
104 | │ ├─┬ string-width@1.0.1
105 | │ │ ├─┬ code-point-at@1.0.0
106 | │ │ │ └── number-is-nan@1.0.0
107 | │ │ └── is-fullwidth-code-point@1.0.0
108 | │ ├── window-size@0.1.4
109 | │ └── y18n@3.2.1
110 | └─┬ source-map-support@0.4.0
111 | └─┬ source-map@0.1.32
112 | └── amdefine@1.0.0
113 |
114 | lein cljsbuild once
115 | Compiling ClojureScript...
116 | Compiling "out/example02.js" from ["src"]...
117 | Successfully compiled "out/example02.js" in 3.075 seconds.
118 | Compilation complete: use "node out/example02.js --help" for execution instructions
119 | ```
120 | This will generate a nodejs application in _out/example02.js_. You may run it with --help to get a command summary.
121 | ```
122 | $ node out/example02.js --help
123 | Usage: example02 [options]
124 |
125 | Options Summary:
126 | --host HOST localhost Host name
127 | --port PORT 3000 Port number
128 | -p, --path PATH Path/URL to the chaincode (deploy only, mutually exclsive with -n)
129 | -n, --name NAME Name of the chaincode (mutually exclusive with -p)
130 | -c, --command CMD check-balance One of [deploy make-payment delete-account check-balance]
131 | -a, --args ARGS JSON formatted arguments to submit
132 | -h, --help
133 | ```
134 | ### Step 4 - Deploy the CAR
135 | We can deploy the CAR we packaged in Step 2 using the "-c deploy" feature of the client. We specify the path the CAR with -p and args with -a.
136 |
137 | ```
138 | $ node ./out/example02.js -c deploy -p /fqp/to/app.car --port 5000 --args '{"partyA":{"entity":"a", "value":100}, "partyB":{"entity":"b", "value":100}}'
139 | ```
140 | This will return something that looks like:
141 | ```
142 | Response: {:result {:status OK, :message a9114852d11579bb6000abd7b2d3b25403aa7ff4f365a80ab2382a1616a066cddacefd3422c62337ba1b5eda2b2f4f04f5a2e3dbd411159db188d6946e83a95b}}
143 | ```
144 | Note the hash that is returned in the {:result {:message}}, as this is your chaincode instance ID or "name".
145 |
146 | #### Note:
147 | -p must be a fully qualified path since it is passed to the VP as is. Future versions of the tool/peer may allow inline data, TBD.
148 |
149 | -a is expected to be a JSON structure that matches the protobuf definition for the request in particular. In this case, we are deploying so we are interested in the _Init_ message within the appinit.proto.
150 |
151 | #####If you started your node with _peer node start --peer-chaincodedev_, deploy your chaintool build like you would with non-chaintool chaincode.
152 | ```
153 | $ CORE_CHAINCODE_ID_NAME=org.hyperledger.chaincode.example02 CORE_PEER_ADDRESS=0.0.0.0:30303 ./app/build/bin/org.hyperledger.chaincode.example02-0.1-SNAPSHOT
154 | $ node ./out/example02.js -c deploy -n org.hyperledger.chaincode.example02 --port 5000 --args '{"partyA":{"entity":"a", "value":100}, "partyB":{"entity":"b", "value":100}}'
155 | ```
156 |
157 | #### Where did the .proto files come from?
158 | _chaintool proto_ was used to generate .proto files from the .cci files defined in ./app/src/interfaces
159 | ### Step 5 - Query our current balances
160 | We can use "-n $hash -c check-balance" to check the balance of one of our accounts
161 | ```
162 | $ node ./out/example02.js -n a9114....946e83a95b --port 5000 -c check-balance --args '{"id":"a"}'
163 | ```
164 | This should return with
165 | ```
166 | Success: Balance = 100
167 | ```
168 | We can repeat the process with id "b". Likewise, we can confirm that the system should return an error for any ids besides "a" or "b".
169 | #### Note:
170 | If you started your node with _peer node start --peer-chaincodedev_, change the hash (_a9114....946e83a95b_) to the name you chose in Step 4.
171 | ```
172 | $ node ./out/example02.js -n org.hyperledger.chaincode.example02 --port 5000 -c check-balance --args '{"id":"a"}'
173 | ```
174 | ### Step 6 - Make a Payment
175 | Now lets transfer 10 tokens from a to b.
176 | ```
177 | $ node ./out/example02.js -n a9114....946e83a95b --port 5000 -c make-payment --args '{ "partySrc": "a", "partyDst": "b", "amount": 10}'
178 | ```
179 | You should be able to repeat the query in Step 5 and confirm that a now holds 90 tokens while b holds 110.
180 |
181 | 
This work is licensed under a Creative Commons Attribution 4.0 International License.
182 |
--------------------------------------------------------------------------------
/examples/example02/app/chaincode.yaml:
--------------------------------------------------------------------------------
1 |
2 | # ----------------------------------
3 | # chaincode example02
4 | # ----------------------------------
5 | #
6 | # Copyright Greg Haskins All Rights Reserved
7 | #
8 | # SPDX-License-Identifier: Apache-2.0
9 | #
10 |
11 | Schema: 1
12 | Name: org.hyperledger.chaincode.example02
13 | Version: 0.1-SNAPSHOT
14 |
15 | Platform:
16 | Name: org.hyperledger.chaincode.golang
17 | Version: 1
18 |
19 | Provides: [self] # 'self' is a keyword that means there should be $name.cci (e.g. org.hyperledger.chaincode.example02.cci)
20 |
--------------------------------------------------------------------------------
/examples/example02/app/src/chaincode/chaincode_example02.go:
--------------------------------------------------------------------------------
1 | /*
2 | SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | package main
6 |
7 | import (
8 | "errors"
9 | "fmt"
10 | "strconv"
11 |
12 | "hyperledger/cci/appinit"
13 | "hyperledger/cci/org/hyperledger/chaincode/example02"
14 | "hyperledger/ccs"
15 |
16 | "github.com/golang/protobuf/proto"
17 | "github.com/hyperledger/fabric/core/chaincode/shim"
18 | )
19 |
20 | type ChaincodeExample struct {
21 | }
22 |
23 | // Called to initialize the chaincode
24 | func (t *ChaincodeExample) Init(stub shim.ChaincodeStubInterface, param *appinit.Init) error {
25 |
26 | var err error
27 |
28 | fmt.Printf("Aval = %d, Bval = %d\n", param.PartyA.Value, param.PartyB.Value)
29 |
30 | // Write the state to the ledger
31 | err = t.PutState(stub, param.PartyA)
32 | if err != nil {
33 | return err
34 | }
35 |
36 | err = t.PutState(stub, param.PartyB)
37 | if err != nil {
38 | return err
39 | }
40 |
41 | return nil
42 | }
43 |
44 | // Transaction makes payment of X units from A to B
45 | func (t *ChaincodeExample) MakePayment(stub shim.ChaincodeStubInterface, param *example02.PaymentParams) error {
46 |
47 | var err error
48 |
49 | // Get the state from the ledger
50 | src, err := t.GetState(stub, param.PartySrc)
51 | if err != nil {
52 | return err
53 | }
54 |
55 | dst, err := t.GetState(stub, param.PartyDst)
56 | if err != nil {
57 | return err
58 | }
59 |
60 | // Perform the execution
61 | X := int(param.Amount)
62 | src = src - X
63 | dst = dst + X
64 | fmt.Printf("Aval = %d, Bval = %d\n", src, dst)
65 |
66 | // Write the state back to the ledger
67 | err = stub.PutState(param.PartySrc, []byte(strconv.Itoa(src)))
68 | if err != nil {
69 | return err
70 | }
71 |
72 | err = stub.PutState(param.PartyDst, []byte(strconv.Itoa(dst)))
73 | if err != nil {
74 | return err
75 | }
76 |
77 | return nil
78 | }
79 |
80 | // Deletes an entity from state
81 | func (t *ChaincodeExample) DeleteAccount(stub shim.ChaincodeStubInterface, param *example02.Entity) error {
82 |
83 | // Delete the key from the state in ledger
84 | err := stub.DelState(param.Id)
85 | if err != nil {
86 | return errors.New("Failed to delete state")
87 | }
88 |
89 | return nil
90 | }
91 |
92 | // Query callback representing the query of a chaincode
93 | func (t *ChaincodeExample) CheckBalance(stub shim.ChaincodeStubInterface, param *example02.Entity) (*example02.BalanceResult, error) {
94 | var err error
95 |
96 | // Get the state from the ledger
97 | val, err := t.GetState(stub, param.Id)
98 | if err != nil {
99 | return nil, err
100 | }
101 |
102 | fmt.Printf("Query Response: %d\n", val)
103 | return &example02.BalanceResult{Balance: *proto.Int32(int32(val))}, nil
104 | }
105 |
106 | func main() {
107 | self := &ChaincodeExample{}
108 | interfaces := ccs.Interfaces {
109 | "org.hyperledger.chaincode.example02": self,
110 | "appinit": self,
111 | }
112 |
113 | err := ccs.Start(interfaces) // Our one instance implements both Transactions and Queries interfaces
114 | if err != nil {
115 | fmt.Printf("Error starting example chaincode: %s", err)
116 | }
117 | }
118 |
119 | //-------------------------------------------------
120 | // Helpers
121 | //-------------------------------------------------
122 | func (t *ChaincodeExample) PutState(stub shim.ChaincodeStubInterface, party *appinit.Party) error {
123 | return stub.PutState(party.Entity, []byte(strconv.Itoa(int(party.Value))))
124 | }
125 |
126 | func (t *ChaincodeExample) GetState(stub shim.ChaincodeStubInterface, entity string) (int, error) {
127 | bytes, err := stub.GetState(entity)
128 | if err != nil {
129 | return 0, errors.New("Failed to get state")
130 | }
131 | if bytes == nil {
132 | return 0, errors.New("Entity not found")
133 | }
134 |
135 | val, _ := strconv.Atoi(string(bytes))
136 | return val, nil
137 | }
138 |
--------------------------------------------------------------------------------
/examples/example02/app/src/interfaces/appinit.cci:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | message Party {
8 | string entity = 1;
9 | int32 value = 2;
10 | }
11 |
12 | message Init {
13 | Party partyA = 1;
14 | Party partyB = 2;
15 | }
16 |
--------------------------------------------------------------------------------
/examples/example02/app/src/interfaces/org.hyperledger.chaincode.example02.cci:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | message PaymentParams {
8 | string partySrc = 1;
9 | string partyDst = 2;
10 | int32 amount = 3;
11 | }
12 |
13 | message Entity {
14 | string id = 1;
15 | }
16 |
17 | message BalanceResult {
18 | int32 balance = 1;
19 | }
20 |
21 | functions {
22 | void MakePayment(PaymentParams) = 1;
23 | void DeleteAccount(Entity) = 2;
24 | BalanceResult CheckBalance(Entity) = 3;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | SRCS = $(shell find src -type f)
8 | LEIN = $(shell which lein || echo ../../../../lein)
9 |
10 | all: client
11 |
12 | client: ./target/nodecljs/main.js
13 |
14 | ./target/nodecljs/main.js: $(SRCS) Makefile
15 | $(LEIN) nodecompile
16 | @echo "Compilation complete: use \"node $@ --help\" for execution instructions"
17 |
18 | clean:
19 | -@rm -rf ./target ||:
20 | -@rm -rf ./node_modules ||:
21 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/project.clj:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 |
7 | (defproject example02 "0.1.0-SNAPSHOT"
8 | :description "FIXME: write this!"
9 | :url "http://example.com/FIXME"
10 | :dependencies [[org.clojure/clojure "1.8.0"]
11 | [org.clojure/clojurescript "1.9.542"]
12 | [org.clojure/tools.cli "0.3.5"]
13 | [funcool/promesa "1.8.1"]]
14 | :plugins [[lein-nodecljs "0.7.0"]]
15 | :npm {:dependencies [[source-map-support "0.4.15"]
16 | [protobufjs "5.0.3"]
17 | [read-yaml "1.1.0"]
18 | [fabric-client "1.0.0-beta"]]}
19 | :source-paths ["src" "target/classes"]
20 | :clean-targets ["out" "release"]
21 | :target-path "target"
22 | :nodecljs {:main example02.main
23 | :files ["protos"]})
24 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/protos/appinit.proto:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by chaintool. DO NOT EDIT!!
3 | //
4 |
5 | syntax = "proto3";
6 |
7 | package appinit;
8 |
9 | message Init {
10 | Party partyA = 1;
11 | Party partyB = 2;
12 | }
13 |
14 | message Party {
15 | string entity = 1;
16 | int32 value = 2;
17 | }
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/protos/org.hyperledger.chaincode.example02.proto:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by chaintool. DO NOT EDIT!!
3 | //
4 |
5 | syntax = "proto3";
6 |
7 | package org.hyperledger.chaincode.example02;
8 |
9 | message BalanceResult {
10 | int32 balance = 1;
11 | }
12 |
13 | message Entity {
14 | string id = 1;
15 | }
16 |
17 | message PaymentParams {
18 | string partySrc = 1;
19 | string partyDst = 2;
20 | int32 amount = 3;
21 | }
22 |
23 |
24 | //
25 | // Available RPC functions exported by this interface
26 | //
27 | // void MakePayment(PaymentParams) -> org.hyperledger.chaincode.example02/txn/1
28 | // void DeleteAccount(Entity) -> org.hyperledger.chaincode.example02/txn/2
29 | // BalanceResult CheckBalance(Entity) -> org.hyperledger.chaincode.example02/query/1
30 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/sample.config:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 | # Sample configuration, originally generated by fabric.git/examples/cluster.
7 | #
8 | ca:
9 | url: https://172.18.0.2:7054
10 | certificate: |
11 | -----BEGIN CERTIFICATE-----
12 | MIICLTCCAdOgAwIBAgIQUtpA1+L1r0wtq2xQbDUD4zAKBggqhkjOPQQDAjBjMQsw
13 | CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
14 | YW5jaXNjbzERMA8GA1UEChMIb3JnMS5uZXQxFDASBgNVBAMTC2NhLm9yZzEubmV0
15 | MB4XDTE3MDUxODEzNDcyNVoXDTI3MDUxNjEzNDcyNVowYzELMAkGA1UEBhMCVVMx
16 | EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xETAP
17 | BgNVBAoTCG9yZzEubmV0MRQwEgYDVQQDEwtjYS5vcmcxLm5ldDBZMBMGByqGSM49
18 | AgEGCCqGSM49AwEHA0IABD7I6vDGG8rDKT8JXNcQ5SibUcAV3LEETbPyVEFIqzmW
19 | FTRt4WP2PBMLmCaWJ1o3imxnQDH5Q4azM31iwkjmGUqjaTBnMA4GA1UdDwEB/wQE
20 | AwIBpjAZBgNVHSUEEjAQBgRVHSUABggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/
21 | MCkGA1UdDgQiBCAZHkKKVsQcda9JgHYhr2lFNOT912AMyD2IawTFPGfwoTAKBggq
22 | hkjOPQQDAgNIADBFAiEA0B+8HPbVBIk1xaxrfaEPaB0soa15IaaVygEIEK5xsuYC
23 | IDx/qwQWsR/F8EeNnrgCRXpT03v74L96pAoUj0Ik4/6q
24 | -----END CERTIFICATE-----
25 |
26 | orderer:
27 | url: grpcs://172.18.0.3:7050
28 | hostname: orderer
29 | ca: |
30 | -----BEGIN CERTIFICATE-----
31 | MIICOjCCAeCgAwIBAgIRAPUydZl5CtViAfdhGxmx3L0wCgYIKoZIzj0EAwIwaTEL
32 | MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
33 | cmFuY2lzY28xFDASBgNVBAoTC29yZGVyZXIubmV0MRcwFQYDVQQDEw5jYS5vcmRl
34 | cmVyLm5ldDAeFw0xNzA1MTgxMzQ3MjVaFw0yNzA1MTYxMzQ3MjVaMGkxCzAJBgNV
35 | BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp
36 | c2NvMRQwEgYDVQQKEwtvcmRlcmVyLm5ldDEXMBUGA1UEAxMOY2Eub3JkZXJlci5u
37 | ZXQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQS4tZgasL3dvFlZZ/tuYjF2EqD
38 | 6831TL21Lg7aCY37jUUjWYVOZoyDQviYaXwPwD6cnOTeQHrSRKVdbP28KOBYo2kw
39 | ZzAOBgNVHQ8BAf8EBAMCAaYwGQYDVR0lBBIwEAYEVR0lAAYIKwYBBQUHAwEwDwYD
40 | VR0TAQH/BAUwAwEB/zApBgNVHQ4EIgQgiip3TGazExyZaoDdbFkJPt0T//SqvzYv
41 | 05KcJc5bZJEwCgYIKoZIzj0EAwIDSAAwRQIhAM514AwlLgB23iSbYfiIOye/Sknx
42 | sBOAts8Q3eiKNS/lAiA6b6dG0ACK87Zwz+WmFGy8idsUz6+VUeZnGn3Q7fUQJA==
43 | -----END CERTIFICATE-----
44 |
45 | peers:
46 | - api: grpcs://172.18.0.4:7051
47 | events: grpcs://172.18.0.4:7053
48 | hostname: peer1
49 | - api: grpcs://172.18.0.7:7051
50 | events: grpcs://172.18.0.7:7053
51 | hostname: peer2
52 | - api: grpcs://172.18.0.5:7051
53 | events: grpcs://172.18.0.5:7053
54 | hostname: peer3
55 | - api: grpcs://172.18.0.6:7051
56 | events: grpcs://172.18.0.6:7053
57 | hostname: peer4
58 |
59 | identity:
60 | principal: Admin@org1.net
61 | mspid: Org1MSP
62 | privatekey: |
63 | -----BEGIN PRIVATE KEY-----
64 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBjZL0WX600IdbNTE
65 | ksDiPDNrfeFWujnL040elNc5PWyhRANCAAReHGXySigTarRxC9yExi+x1kkUQ5Ek
66 | vl01POTbj/zUr/rBcYFbcr0VofanA7bs7v2sNBLu4XKrcMtZhM1kGe8E
67 | -----END PRIVATE KEY-----
68 | certificate: |
69 | -----BEGIN CERTIFICATE-----
70 | MIICFjCCAbygAwIBAgIQQmDezE6sFW+liP/mJyPGZDAKBggqhkjOPQQDAjBjMQsw
71 | CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
72 | YW5jaXNjbzERMA8GA1UEChMIb3JnMS5uZXQxFDASBgNVBAMTC2NhLm9yZzEubmV0
73 | MB4XDTE3MDUxODEzNDcyNVoXDTI3MDUxNjEzNDcyNVowUzELMAkGA1UEBhMCVVMx
74 | EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xFzAV
75 | BgNVBAMMDkFkbWluQG9yZzEubmV0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
76 | Xhxl8kooE2q0cQvchMYvsdZJFEORJL5dNTzk24/81K/6wXGBW3K9FaH2pwO27O79
77 | rDQS7uFyq3DLWYTNZBnvBKNiMGAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
78 | CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgGR5CilbEHHWvSYB2
79 | Ia9pRTTk/ddgDMg9iGsExTxn8KEwCgYIKoZIzj0EAwIDSAAwRQIhANvdmrxyJOgG
80 | 9pCcqm5j882lPYrb0+e7lY6jWgfyPBfOAiArov4lrvavFoHZzxZefqxUJFWbty5I
81 | w8+qlZElFL0fyg==
82 | -----END CERTIFICATE-----
83 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/example02/api.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns example02.api
7 | (:require [example02.protobuf :as pb]
8 | [example02.rpc :as rpc]
9 | [promesa.core :as p :include-macros true]))
10 |
11 | (def intf-name "org.hyperledger.chaincode.example02")
12 |
13 | (def all-interfaces ["appinit" intf-name])
14 |
15 | (defn init [dir]
16 | (pb/init dir all-interfaces))
17 |
18 | (defn install [context]
19 | (-> (rpc/install context)
20 | (p/then #(println "Success!"))))
21 |
22 | (defn instantiate [{:keys [args] :as context}]
23 | (let [proto (pb/get "appinit")]
24 | (-> context
25 | (assoc :func "init"
26 | :args (proto.Init. args))
27 | rpc/instantiate
28 | (p/then #(println "Success!")))))
29 |
30 | (defn make-payment [{:keys [args] :as context}]
31 | (let [proto (pb/get intf-name)]
32 | (-> context
33 | (assoc :func "org.hyperledger.chaincode.example02/fcn/1"
34 | :args (proto.PaymentParams. args))
35 | rpc/transaction
36 | (p/then #(println "Success!")))))
37 |
38 | (defn delete-account [{:keys [args] :as context}]
39 | (let [proto (pb/get intf-name)]
40 | (-> context
41 | (assoc :func "org.hyperledger.chaincode.example02/fcn/2"
42 | :args (proto.Entity. args))
43 | rpc/transaction
44 | (p/then #(println "Success!")))))
45 |
46 | (defn check-balance [{:keys [args] :as context}]
47 | (let [proto (pb/get intf-name)]
48 | (-> context
49 | (assoc :func "org.hyperledger.chaincode.example02/fcn/3"
50 | :args (proto.Entity. args))
51 | rpc/query
52 | (p/then #(println "Success: Balance ="
53 | (->> % first proto.BalanceResult.decode64 .-balance))))))
54 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/example02/connection.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns example02.connection
7 | (:require [fabric-sdk.core :as fabric]
8 | [fabric-sdk.channel :as fabric.channel]
9 | [fabric-sdk.eventhub :as fabric.eventhub]
10 | [fabric-sdk.user :as fabric.user]
11 | [promesa.core :as p :include-macros true]))
12 |
13 | (defn- set-state-store [client path]
14 | (-> (fabric/new-default-kv-store path)
15 | (p/then #(fabric/set-state-store client %))))
16 |
17 | (defn- create-user [client identity]
18 | (let [config #js {:username (:principal identity)
19 | :mspid (:mspid identity)
20 | :cryptoContent #js {:privateKeyPEM (:privatekey identity)
21 | :signedCertPEM (:certificate identity)}}]
22 |
23 | (fabric/create-user client config)))
24 |
25 | (defn- connect-orderer [client channel config]
26 | (let [{:keys [ca hostname url]} (:orderer config)
27 | orderer (fabric/new-orderer client
28 | url
29 | #js {:pem ca
30 | :ssl-target-name-override hostname})]
31 |
32 | (fabric.channel/add-orderer channel orderer)
33 |
34 | orderer))
35 |
36 | (defn- connect-peer [client channel config peercfg]
37 | (let [ca (-> config :ca :certificate)
38 | {:keys [api hostname]} peercfg
39 | peer (fabric/new-peer client
40 | api
41 | #js {:pem ca
42 | :ssl-target-name-override hostname
43 | :request-timeout 120000})]
44 |
45 | (fabric.channel/add-peer channel peer)
46 |
47 | peer))
48 |
49 | (defn- connect-eventhub [client channel config]
50 | (let [ca (-> config :ca :certificate)
51 | {:keys [events hostname]} (-> config :peers first)
52 | eventhub (fabric/new-eventhub client)]
53 |
54 | (fabric.eventhub/set-peer-addr eventhub
55 | events
56 | #js {:pem ca
57 | :ssl-target-name-override hostname})
58 | (fabric.eventhub/connect! eventhub)
59 |
60 | eventhub))
61 |
62 | (defn connect! [{:keys [config id channelId] :as options}]
63 |
64 | (let [client (fabric/new-client)
65 | identity (:identity config)]
66 |
67 | (-> (set-state-store client ".hfc-kvstore")
68 | (p/then #(create-user client identity))
69 | (p/then (fn [user]
70 |
71 | (let [channel (fabric.channel/new client channelId)
72 | orderer (connect-orderer client channel config)
73 | peers (->> config
74 | :peers
75 | (map #(connect-peer client channel config %)))
76 | eventhub (connect-eventhub client channel config)]
77 |
78 | (-> (fabric.channel/initialize channel)
79 | (p/then (fn []
80 | {:client client
81 | :channel channel
82 | :orderer orderer
83 | :peers peers
84 | :eventhub eventhub
85 | :user user})))))))))
86 |
87 | (defn disconnect! [{:keys [eventhub]}]
88 | (fabric.eventhub/disconnect! eventhub))
89 |
90 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/example02/main.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns example02.main
7 | (:require [clojure.string :as string]
8 | [cljs.nodejs :as nodejs]
9 | [cljs.tools.cli :refer [parse-opts]]
10 | [example02.connection :as conn]
11 | [example02.api :as api]
12 | [promesa.core :as p :include-macros true]))
13 |
14 | (nodejs/enable-util-print!)
15 |
16 | (def fs (nodejs/require "fs"))
17 | (def pathlib (nodejs/require "path"))
18 | (def readyaml (nodejs/require "read-yaml"))
19 |
20 | (def _commands
21 | [["install"
22 | {:fn api/install}]
23 | ["instantiate"
24 | {:fn api/instantiate
25 | :default-args #js {:partyA #js {:entity "A"
26 | :value 100}
27 | :partyB #js {:entity "B"
28 | :value 200}}}]
29 | ["make-payment"
30 | {:fn api/make-payment
31 | :default-args #js {:partySrc "A"
32 | :partyDst "B"
33 | :amount 10}}]
34 | ["delete-account"
35 | {:fn api/delete-account
36 | :default-args #js {:id "A"}}]
37 | ["check-balance"
38 | {:fn api/check-balance
39 | :default-args #js {:id "A"}}]])
40 |
41 | (def commands (into {} _commands))
42 | (defn print-commands [] (->> commands keys vec print-str))
43 |
44 | (def options
45 | [[nil "--config CONFIG" "path/to/client.config"]
46 | ["-p" "--path ID" "path/to/chaincode.car ('install' only)"]
47 | ["-i" "--chaincodeId ID" "ChaincodeID"
48 | :default "mycc"]
49 | ["-v" "--version VERSION" "Chaincode version"
50 | :default "1"]
51 | [nil "--channelId ID" "Channel ID"
52 | :default "mychannel"]
53 | ["-c" "--command CMD" (str "One of " (print-commands))
54 | :default "check-balance"
55 | :validate [#(contains? commands %) (str "Supported commands: " (print-commands))]]
56 | ["-a" "--args ARGS" "JSON formatted arguments to submit"]
57 | ["-h" "--help"]])
58 |
59 | (defn exit [status msg & rest]
60 | (do
61 | (apply println msg rest)
62 | status))
63 |
64 | (defn prep-usage [msg] (->> msg flatten (string/join \newline)))
65 |
66 | (defn usage [options-summary]
67 | (prep-usage ["Usage: example02 [options]"
68 | ""
69 | "Options Summary:"
70 | options-summary
71 | ""]))
72 |
73 | (defn- exist? [path]
74 | (try
75 | (.statSync fs path)
76 | (catch js/Object e
77 | nil)))
78 |
79 | (defn -main [& args]
80 | ;; Initialize the protobuf layer, etc
81 | (api/init (.resolve pathlib js/__dirname ".." "protos"))
82 |
83 | (let [{:keys [options arguments errors summary]} (parse-opts args options)
84 | {:keys [config command args]} options]
85 | (cond
86 |
87 | (:help options)
88 | (exit 0 (usage summary))
89 |
90 | (not= errors nil)
91 | (exit -1 "Error: " (string/join errors))
92 |
93 | (nil? config)
94 | (exit -1 "Error: --config required (see --help)")
95 |
96 | (not (exist? config))
97 | (exit -1 (str "Error: config \"" config "\" not found"))
98 |
99 | :else
100 | (let [desc (commands command)
101 | _args (if (empty? arguments)
102 | (:default-args desc)
103 | (->> arguments first (.parse js/JSON)))
104 | _config (-> (.sync readyaml config)
105 | (js->clj :keywordize-keys true))]
106 |
107 | (p/alet [context (p/await (conn/connect! (assoc options :config _config)))
108 | params (-> options
109 | (assoc :args _args)
110 | (merge context))]
111 |
112 | (println (str "Running " command "(" (.stringify js/JSON _args) ")"))
113 |
114 | ;; Run the subcommand funtion
115 | (-> ((:fn desc) params)
116 | (p/catch #(println "Error:" %))
117 | (p/then #(conn/disconnect! context))))))))
118 |
119 | (set! *main-cli-fn* -main)
120 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/example02/protobuf.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns example02.protobuf
7 | (:require [cljs.nodejs :as nodejs])
8 | (:refer-clojure :exclude [get]))
9 |
10 | (def path (nodejs/require "path"))
11 | (def pb (nodejs/require "protobufjs"))
12 |
13 | (def builder (.newBuilder pb))
14 |
15 | (defn- load [dir name]
16 | (let [path (.resolve path dir (str name ".proto"))]
17 | (.loadProtoFile pb path builder)
18 | (.build builder name)))
19 |
20 | (def protos (atom {}))
21 |
22 | (defn get [name]
23 | (@protos name))
24 |
25 | (defn init [dir interfaces]
26 | (let [entries (->> interfaces
27 | (map #(vector % (load dir %)))
28 | (into {}))]
29 | (swap! protos merge entries)))
30 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/example02/rpc.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns example02.rpc
7 | (:require [cljs.nodejs :as nodejs]
8 | [fabric-sdk.core :as fabric]
9 | [fabric-sdk.channel :as fabric.channel]
10 | [fabric-sdk.eventhub :as fabric.eventhub]
11 | [promesa.core :as p :include-macros true]))
12 |
13 | (defn- create-base-request [{:keys [client peers channelId chaincodeId]}]
14 | (let [txid (fabric/new-txnid client)]
15 |
16 | {:chaincodeType "car"
17 | :targets peers
18 | :chainId channelId
19 | :chaincodeId chaincodeId
20 | :txId txid}))
21 |
22 | (defn- create-request [{:keys [func args] :as options}]
23 | (-> (create-base-request options)
24 | (assoc :fcn func :args #js [(.toBuffer args)])))
25 |
26 | (defn- decodejs [js]
27 | (js->clj js :keywordize-keys true))
28 |
29 | (defn- verify-results [[results proposal header :as response]]
30 | (doseq [result results]
31 | (let [retval (-> result decodejs :response :status)]
32 | (when-not (= retval 200)
33 | (throw result))))
34 |
35 | response)
36 |
37 | (defn- register-tx-event [eventhub txid]
38 | (p/promise
39 | (fn [resolve reject]
40 | (fabric.eventhub/register-tx-event eventhub txid resolve))))
41 |
42 | (defn- send-transaction [{:keys [channel response]}]
43 | (let [[results proposal header] response]
44 | (fabric.channel/send-transaction channel
45 | #js {:proposalResponses results
46 | :proposal proposal
47 | :header header})))
48 |
49 | (defn- forward-endorsements [{:keys [eventhub request tmo] :as options}]
50 | (let [txid (-> request decodejs :txId)]
51 | (-> (p/all [(register-tx-event eventhub txid)
52 | (send-transaction options)])
53 | (p/timeout tmo))))
54 |
55 | (defn install [{:keys [client channel path version] :as options}]
56 | (let [request (-> (create-base-request options)
57 | (assoc :chaincodeVersion version
58 | :chaincodePath path)
59 | clj->js)]
60 |
61 | (when (not path)
62 | (fabric.channel/set-dev-mode channel true))
63 |
64 | (-> (fabric/install-chaincode client request)
65 | (p/then verify-results))))
66 |
67 | (defn instantiate [{:keys [client channel version] :as options}]
68 | (let [request (-> (create-request options)
69 | (assoc :chaincodeVersion version)
70 | clj->js)]
71 |
72 | (-> (fabric.channel/send-instantiate-proposal channel request)
73 | (p/then verify-results)
74 | (p/then #(forward-endorsements (assoc options
75 | :request request
76 | :response %
77 | :tmo 120000))))))
78 |
79 | (defn transaction [{:keys [client channel] :as options}]
80 | (let [request (-> options create-request clj->js)]
81 |
82 | (-> (fabric.channel/send-transaction-proposal channel request)
83 | (p/then verify-results)
84 | (p/then #(forward-endorsements (assoc options
85 | :request request
86 | :response %
87 | :tmo 30000))))))
88 |
89 | (defn query [{:keys [client channel] :as options}]
90 | (let [request (-> options create-request clj->js)]
91 | (fabric.channel/query-by-chaincode channel request)))
92 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/fabric_sdk/channel.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns fabric-sdk.channel
7 | (:require-macros [fabric-sdk.macros :as m])
8 | (:require [promesa.core :as p :include-macros true]))
9 |
10 | (defn new [client name]
11 | (.newChannel client name))
12 |
13 | (defn initialize [channel]
14 | (m/pwrap (.initialize channel)))
15 |
16 | (defn add-peer [channel instance]
17 | (.addPeer channel instance))
18 |
19 | (defn add-orderer [channel instance]
20 | (.addOrderer channel instance))
21 |
22 | (defn set-dev-mode [channel enabled]
23 | (.setDevMode channel enabled))
24 |
25 | (defn send-instantiate-proposal [channel request]
26 | (m/pwrap (.sendInstantiateProposal channel request)))
27 |
28 | (defn send-transaction-proposal [channel request]
29 | (m/pwrap (.sendTransactionProposal channel request)))
30 |
31 | (defn send-transaction [channel request]
32 | (m/pwrap (.sendTransaction channel request)))
33 |
34 | (defn query-by-chaincode [channel request]
35 | (m/pwrap (.queryByChaincode channel request)))
36 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/fabric_sdk/core.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns fabric-sdk.core
7 | (:require-macros [fabric-sdk.macros :as m])
8 | (:require [cljs.nodejs :as nodejs]
9 | [promesa.core :as p :include-macros true]))
10 |
11 | (def hfc (nodejs/require "fabric-client"))
12 |
13 | (defn new-client []
14 | (new hfc))
15 |
16 | (defn new-default-kv-store [path]
17 | (m/pwrap (.newDefaultKeyValueStore hfc #js {:path path})))
18 |
19 | (defn set-state-store [client store]
20 | (.setStateStore client store))
21 |
22 | (defn install-chaincode [client request]
23 | (m/pwrap (.installChaincode client request)))
24 |
25 | (defn get-user-context [client username]
26 | (m/pwrap (.getUserContext client username)))
27 |
28 | (defn set-user-context [client user]
29 | (m/pwrap (.setUserContext client user)))
30 |
31 | (defn create-user [client spec]
32 | (m/pwrap (.createUser client spec)))
33 |
34 | (defn new-orderer [client url opts]
35 | (.newOrderer client url opts))
36 |
37 | (defn new-peer [client url opts]
38 | (.newPeer client url opts))
39 |
40 | (defn new-eventhub [client]
41 | (.newEventHub client))
42 |
43 | (defn new-txnid [client]
44 | (.newTransactionID client))
45 |
46 |
47 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/fabric_sdk/eventhub.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns fabric-sdk.eventhub
7 | (:require-macros [fabric-sdk.macros :as m])
8 | (:require [cljs.nodejs :as nodejs]
9 | [promesa.core :as p :include-macros true]))
10 |
11 | (defn set-peer-addr [instance addr opts]
12 | (.setPeerAddr instance addr opts))
13 |
14 | (defn connect! [instance]
15 | (.connect instance))
16 |
17 | (defn disconnect! [instance]
18 | (.disconnect instance))
19 |
20 | (defn register-tx-event [instance txid cb]
21 | (.registerTxEvent instance (.getTransactionID txid) cb))
22 |
23 | (defn unregister-tx-event [instance txid]
24 | (.unregisterTxEvent instance txid))
25 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/fabric_sdk/macros.clj:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns fabric-sdk.macros
7 | (:require [promesa.core :as promesa]))
8 |
9 | (defmacro wrapped-resolve [expr exec result]
10 | `(do
11 | (comment (println "expr:" ~expr "resolved with" ~result))
12 | (~exec ~result)))
13 |
14 | (defmacro wrapped-reject [expr exec result]
15 | `(do
16 | (comment (println "expr:" ~expr "rejected with" ~result))
17 | (~exec ~result)))
18 |
19 | (defmacro pwrap
20 | ;; Implements an interop wrapper between JS promise and promesa
21 | [expr]
22 | `(promesa/promise
23 | (fn [resolve# reject#]
24 | (-> ~expr
25 | (.then #(wrapped-resolve '~expr resolve# %)
26 | #(wrapped-reject '~expr reject# %))))))
27 |
--------------------------------------------------------------------------------
/examples/example02/client/cljs/src/fabric_sdk/user.cljs:
--------------------------------------------------------------------------------
1 | ;;-----------------------------------------------------------------------------
2 | ;; Copyright 2017 Greg Haskins
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;-----------------------------------------------------------------------------
6 | (ns fabric-sdk.user
7 | (:require-macros [fabric-sdk.macros :as m])
8 | (:require [cljs.nodejs :as nodejs]
9 | [promesa.core :as p :include-macros true]))
10 |
11 | (def user (nodejs/require "fabric-client/lib/User.js"))
12 |
13 | (defn new [username client]
14 | (new user username client))
15 |
16 | (defn enrolled? [user]
17 | (and user (.isEnrolled user)))
18 |
19 | (defn set-enrollment [user enrollment mspid]
20 | (m/pwrap (.setEnrollment user enrollment.key enrollment.certificate mspid)))
21 |
--------------------------------------------------------------------------------
/examples/example02/client/nodejs/client.config:
--------------------------------------------------------------------------------
1 | #
2 | # Generated by fabric.git/examples/cluster. DO NOT EDIT!
3 | #
4 | ca:
5 | url: https://172.18.0.7:7054
6 | certificate: |
7 | -----BEGIN CERTIFICATE-----
8 | MIICLTCCAdOgAwIBAgIQbZqIuH0sxAe5sOEv0aHulDAKBggqhkjOPQQDAjBjMQsw
9 | CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
10 | YW5jaXNjbzERMA8GA1UEChMIb3JnMS5uZXQxFDASBgNVBAMTC2NhLm9yZzEubmV0
11 | MB4XDTE3MDYxMDAyMDUzNloXDTI3MDYwODAyMDUzNlowYzELMAkGA1UEBhMCVVMx
12 | EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xETAP
13 | BgNVBAoTCG9yZzEubmV0MRQwEgYDVQQDEwtjYS5vcmcxLm5ldDBZMBMGByqGSM49
14 | AgEGCCqGSM49AwEHA0IABM5lOq+s74ewepmPIxkcpvN0Invb9e22jCHfGsWlxL0i
15 | cVIHTdlaE8oD4XDtwdnjQTjji1+Nc2BEORI8h25RDwajaTBnMA4GA1UdDwEB/wQE
16 | AwIBpjAZBgNVHSUEEjAQBgRVHSUABggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/
17 | MCkGA1UdDgQiBCBrkiWWM7/ttPLO3BM5dZLW8MJBFp51O2/meAhnpyvL3jAKBggq
18 | hkjOPQQDAgNIADBFAiEA2v1aIR8hzhfZuT00AK7cRnuREBspMzBITo17whAZPkQC
19 | IBpkXzLkW8gkSwDa2GICV+QherD8ULoIeugiFiT2jl3a
20 | -----END CERTIFICATE-----
21 |
22 | orderer:
23 | url: grpcs://172.18.0.3:7050
24 | hostname: orderer
25 | ca: |
26 | -----BEGIN CERTIFICATE-----
27 | MIICOTCCAd+gAwIBAgIQAuJaGGTw7AVlD2xsFaZNNzAKBggqhkjOPQQDAjBpMQsw
28 | CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
29 | YW5jaXNjbzEUMBIGA1UEChMLb3JkZXJlci5uZXQxFzAVBgNVBAMTDmNhLm9yZGVy
30 | ZXIubmV0MB4XDTE3MDYxMDAyMDUzNloXDTI3MDYwODAyMDUzNlowaTELMAkGA1UE
31 | BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lz
32 | Y28xFDASBgNVBAoTC29yZGVyZXIubmV0MRcwFQYDVQQDEw5jYS5vcmRlcmVyLm5l
33 | dDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKnGqAQxgKs1fIw9psv126uogyAX
34 | xNLUFOtt0P3NtY+0ThtpFaYz5n4EN5cvMfjfBEsoKq1XApxKmR8siKkxoVajaTBn
35 | MA4GA1UdDwEB/wQEAwIBpjAZBgNVHSUEEjAQBgRVHSUABggrBgEFBQcDATAPBgNV
36 | HRMBAf8EBTADAQH/MCkGA1UdDgQiBCDxJaXPT40u0OY78WSM5yNMAWJl6qDCu4rJ
37 | Tk6iJyLspjAKBggqhkjOPQQDAgNIADBFAiEAuWk3RjJYIqD36Hhnf+gbUGeyaBIf
38 | F8OMZKg0K3g4gFUCIB88GcERpLoYALQfIH21QXkXQfZa33N25HRGNqAlsQxO
39 | -----END CERTIFICATE-----
40 |
41 | peers:
42 | - api: grpcs://172.18.0.2:7051
43 | events: grpcs://172.18.0.2:7053
44 | hostname: peer1
45 | - api: grpcs://172.18.0.4:7051
46 | events: grpcs://172.18.0.4:7053
47 | hostname: peer2
48 | - api: grpcs://172.18.0.5:7051
49 | events: grpcs://172.18.0.5:7053
50 | hostname: peer3
51 | - api: grpcs://172.18.0.6:7051
52 | events: grpcs://172.18.0.6:7053
53 | hostname: peer4
54 |
55 | identity:
56 | principal: Admin@org1.net
57 | mspid: Org1MSP
58 | privatekey: |
59 | -----BEGIN PRIVATE KEY-----
60 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgIiUNEYZ8dVBzU+jE
61 | NYMixzeqk68Pu7lZxfQsJGtvK2ahRANCAARlTUeEVsOclueRBacRCVRVd1t7O3kD
62 | BnshXhEyM0qOrtC4sVnqIAuQ6tN+tD1F+aN5ryRtF6h608/P+wYzOrBb
63 | -----END PRIVATE KEY-----
64 | certificate: |
65 | -----BEGIN CERTIFICATE-----
66 | MIICFjCCAb2gAwIBAgIRAN5coFIxZO/llH5axPB4xL8wCgYIKoZIzj0EAwIwYzEL
67 | MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
68 | cmFuY2lzY28xETAPBgNVBAoTCG9yZzEubmV0MRQwEgYDVQQDEwtjYS5vcmcxLm5l
69 | dDAeFw0xNzA2MTAwMjA1MzZaFw0yNzA2MDgwMjA1MzZaMFMxCzAJBgNVBAYTAlVT
70 | MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRcw
71 | FQYDVQQDDA5BZG1pbkBvcmcxLm5ldDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
72 | BGVNR4RWw5yW55EFpxEJVFV3W3s7eQMGeyFeETIzSo6u0LixWeogC5Dq0360PUX5
73 | o3mvJG0XqHrTz8/7BjM6sFujYjBgMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAK
74 | BggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIGuSJZYzv+208s7c
75 | Ezl1ktbwwkEWnnU7b+Z4CGenK8veMAoGCCqGSM49BAMCA0cAMEQCID6/7BaU5mgk
76 | 7cOC46IFcMyy7ZNMacusZdhmhVZA6pJcAiAsCUSK7JoR/7rWiALb+O0HQFxzoIY9
77 | x931TuD1P0leyQ==
78 | -----END CERTIFICATE-----
79 |
--------------------------------------------------------------------------------
/examples/example02/client/nodejs/client.js:
--------------------------------------------------------------------------------
1 | /*
2 | #
3 | # Copyright Greg Haskins All Rights Reserved
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 | #
7 | */
8 | var program = require('commander');
9 | var pb = require("protobufjs");
10 |
11 | var builder = pb.newBuilder({ convertFieldsToCamelCase: true });
12 |
13 | pb.loadProtoFile("./protos/appinit.proto", builder);
14 | var init = builder.build("appinit");
15 |
16 | pb.loadProtoFile("./protos/org.hyperledger.chaincode.example02.proto", builder);
17 | var app = builder.build("org.hyperledger.chaincode.example02");
18 |
19 | var path = require('path');
20 | var ReadYaml = require('read-yaml');
21 |
22 | var hfc = require('fabric-client');
23 | var hfcutils = require('fabric-client/lib/utils.js');
24 | var utils = require('./lib/util.js');
25 | var Peer = require('fabric-client/lib/Peer.js');
26 | var Orderer = require('fabric-client/lib/Orderer.js');
27 | var EventHub = require('fabric-client/lib/EventHub.js');
28 | var User = require('fabric-client/lib/User.js');
29 |
30 | var client;
31 | var chain;
32 | var peers = [];
33 | var eventhub;
34 |
35 | var channelId = 'mychannel';
36 |
37 | var config = ReadYaml.sync('client.config');
38 |
39 | function createBaseRequest() {
40 | var tx_id = client.newTransactionID();
41 |
42 | // send proposal to endorser
43 | var request = {
44 | chaincodeType: 'car',
45 | targets: peers,
46 | chainId: channelId,
47 | chaincodeId: 'mycc',
48 | txId: tx_id
49 | };
50 |
51 | return request;
52 | }
53 |
54 | function createRequest(fcn, args) {
55 | var request = createBaseRequest();
56 |
57 | request.fcn = fcn;
58 | request.args = [args.toBuffer()];
59 |
60 | return request;
61 | }
62 |
63 | function connect() {
64 | client = new hfc();
65 |
66 | return utils.setStateStore(client, ".hfc-kvstore")
67 | .then(() => {
68 | chain = client.newChannel(channelId);
69 |
70 | chain.addOrderer(client.newOrderer(config.orderer.url, {
71 | pem: config.orderer.ca,
72 | 'ssl-target-name-override': config.orderer.hostname
73 | }));
74 |
75 | for (var i in config.peers) {
76 | var p = config.peers[i]
77 | peer = client.newPeer(p.api, {
78 | pem: config.ca.certificate,
79 | 'ssl-target-name-override': p.hostname,
80 | 'request-timeout': 120000
81 | });
82 | peers.push(peer);
83 | chain.addPeer(peer);
84 | }
85 |
86 | var userSpec = {
87 | username: config.identity.principal,
88 | mspid: config.identity.mspid,
89 | cryptoContent: {
90 | privateKeyPEM: config.identity.privatekey,
91 | signedCertPEM: config.identity.certificate
92 | }};
93 | return client.createUser(userSpec);
94 | })
95 | .then((user) => {
96 | var peer1 = config.peers[0]
97 | eventhub = client.newEventHub();
98 | eventhub.setPeerAddr(peer1.events, {
99 | pem: config.ca.certificate,
100 | 'ssl-target-name-override': peer1.hostname
101 | });
102 | eventhub.connect();
103 |
104 | return chain.initialize()
105 | .then(() => {
106 |
107 | return user;
108 | });
109 | });
110 | }
111 |
112 | function disconnect() {
113 | return new Promise((resolve, reject) => {
114 | eventhub.disconnect();
115 | resolve();
116 | });
117 | }
118 |
119 | function sendInstall(path, version) {
120 |
121 | var request = createBaseRequest();
122 | if (path) {
123 | request.chaincodePath = path;
124 | } else {
125 | chain.setDevMode(true);
126 | }
127 |
128 | console.log(version);
129 | request.chaincodeVersion = "1";
130 |
131 | // send proposal to endorser
132 | return client.installChaincode(request);
133 | }
134 |
135 | function sendInstantiate(args) {
136 |
137 | var request = createRequest('init', new init.Init(args));
138 | request.chaincodeVersion = "1";
139 |
140 | // send proposal to endorser
141 | return chain.sendInstantiateProposal(request)
142 | .then((response) => {
143 | return utils.processResponse(chain, eventhub, request, response, 120000);
144 | });
145 | }
146 |
147 | function sendTransaction(fcn, args) {
148 |
149 | var request = createRequest(fcn, args);
150 |
151 | return chain.sendTransactionProposal(request)
152 | .then((response) => {
153 | return utils.processResponse(chain, eventhub, request, response, 20000);
154 | });
155 | }
156 |
157 | function sendQuery(fcn, args) {
158 | var request = createRequest(fcn, args);
159 | return chain.queryByChaincode(request);
160 | }
161 |
162 | function makePayment(args) {
163 | return sendTransaction('org.hyperledger.chaincode.example02/fcn/1',
164 | new app.PaymentParams(args));
165 | }
166 |
167 | function checkBalance(args) {
168 | return sendQuery('org.hyperledger.chaincode.example02/fcn/3',
169 | new app.Entity(args))
170 | .then((results) => {
171 | return app.BalanceResult.decode(results[0]);
172 | });
173 | }
174 |
175 | program
176 | .version('0.0.1');
177 |
178 | program
179 | .command('install')
180 | .option("-p, --path ", "Path to chaincode.car")
181 | .option("-v, --version ", "Version of chaincode to install")
182 | .action((options) => {
183 | return connect()
184 | .then(() => {
185 | return sendInstall(options.path, options.version);
186 | })
187 | .then(() => {
188 | return disconnect();
189 | })
190 | .catch((err) => {
191 | console.log("error:" + err);
192 | });
193 | });
194 |
195 | program
196 | .command('instantiate')
197 | .action(() => {
198 | return connect()
199 | .then(() => {
200 | return sendInstantiate({
201 | 'partyA': {'entity':'A', 'value':100},
202 | 'partyB': {'entity':'B', 'value':200}
203 | });
204 | })
205 | .then(() => {
206 | return disconnect();
207 | })
208 | .catch((err) => {
209 | console.log("error:" + err);
210 | });
211 | });
212 |
213 | program
214 | .command('makepayment ')
215 | .action((partySrc, partyDst, amount) => {
216 | return connect()
217 | .then(() => {
218 | return makePayment({
219 | 'partySrc': partySrc,
220 | 'partyDst': partyDst,
221 | 'amount': parseInt(amount)
222 | });
223 | })
224 | .then(() => {
225 | return disconnect();
226 | })
227 | .catch((err) => {
228 | console.log("error:" + err);
229 | });
230 | });
231 |
232 | program
233 | .command('checkbalance ')
234 | .action((id) => {
235 | return connect()
236 | .then(() => {
237 | return checkBalance({'id':id});
238 | })
239 | .then((result) => {
240 | console.log("balance:" + result.balance);
241 | return disconnect();
242 | })
243 | .catch((err) => {
244 | console.log("error:" + err);
245 | });
246 | });
247 |
248 |
249 | program.parse(process.argv);
250 |
--------------------------------------------------------------------------------
/examples/example02/client/nodejs/lib/util.js:
--------------------------------------------------------------------------------
1 | var hfc = require('fabric-client');
2 | var utils = require('fabric-client/lib/utils.js');
3 | var User = require('fabric-client/lib/User.js');
4 |
5 | function registerTxEvent(eventhub, txid, tmo) {
6 | return new Promise((resolve, reject) => {
7 |
8 | var handle = setTimeout(() => {
9 | eventhub.unregisterTxEvent(txid);
10 | reject("Timeout!");
11 | }, tmo);
12 |
13 | eventhub.registerTxEvent(txid, (tx, code) => {
14 | resolve(code);
15 | eventhub.unregisterTxEvent(txid);
16 | clearTimeout(handle);
17 | });
18 | });
19 | }
20 |
21 | function sendTransaction(chain, results) {
22 | var proposalResponses = results[0];
23 | var proposal = results[1];
24 | var header = results[2];
25 | var all_good = true;
26 |
27 | for(var i in proposalResponses) {
28 | let one_good = false;
29 |
30 | if (proposalResponses &&
31 | proposalResponses[0].response &&
32 | proposalResponses[0].response.status === 200) {
33 |
34 | one_good = true;
35 | }
36 | all_good = all_good & one_good;
37 | }
38 |
39 | if (all_good) {
40 | var request = {
41 | proposalResponses: proposalResponses,
42 | proposal: proposal,
43 | header: header
44 | };
45 | return chain.sendTransaction(request);
46 | } else {
47 | return Promise.reject("bad result:" + results);
48 | }
49 | }
50 |
51 | module.exports = {
52 | setStateStore: (client, path) => {
53 | return new Promise((resolve, reject) => {
54 | return hfc.newDefaultKeyValueStore({path: path})
55 | .then((store) => {
56 | client.setStateStore(store);
57 | resolve(true);
58 | });
59 | });
60 | },
61 |
62 | getUser: (client, cop, mspid, username, password) => {
63 | return client.getUserContext(username, true)
64 | .then((user) => {
65 | if (user && user.isEnrolled()) {
66 | return Promise.resolve(user);
67 | } else {
68 | // need to enroll it with COP server
69 | return cop.enroll({
70 | enrollmentID: username,
71 | enrollmentSecret: password
72 | }).then((enrollment) => {
73 | var member = new User(username, client);
74 | return member.setEnrollment(enrollment.key,
75 | enrollment.certificate,
76 | mspid)
77 | .then(() => {
78 | return client.setUserContext(member);
79 | });
80 | });
81 | }
82 | });
83 | },
84 |
85 | processResponse: (chain, eventhub, request, response, tmo) => {
86 | return Promise.all(
87 | [registerTxEvent(eventhub, request.txId.getTransactionID(), tmo),
88 | sendTransaction(chain, response)]);
89 | }
90 | };
91 |
--------------------------------------------------------------------------------
/examples/example02/client/nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chaintool-example02",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "client.js",
6 | "dependencies": {
7 | "protobufjs":">=5.0.3",
8 | "commander":"2.9.0",
9 | "winston":"2.3.1",
10 | "read-yaml":"1.1.0",
11 | "fabric-client":"1.0.0-beta"
12 | },
13 | "files": [
14 | "protos",
15 | "lib"
16 | ],
17 | "scripts": {
18 | "test": "echo \"Error: no test specified\" && exit 1"
19 | },
20 | "author": "",
21 | "license": "Apache-2.0"
22 | }
23 |
--------------------------------------------------------------------------------
/examples/example02/client/nodejs/protos/appinit.proto:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by chaintool. DO NOT EDIT!!
3 | //
4 |
5 | syntax = "proto3";
6 |
7 | package appinit;
8 |
9 | message Init {
10 | Party partyA = 1;
11 | Party partyB = 2;
12 | }
13 |
14 | message Party {
15 | string entity = 1;
16 | int32 value = 2;
17 | }
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/example02/client/nodejs/protos/org.hyperledger.chaincode.example02.proto:
--------------------------------------------------------------------------------
1 | //
2 | // Generated by chaintool. DO NOT EDIT!!
3 | //
4 |
5 | syntax = "proto3";
6 |
7 | package org.hyperledger.chaincode.example02;
8 |
9 | message BalanceResult {
10 | int32 balance = 1;
11 | }
12 |
13 | message Entity {
14 | string id = 1;
15 | }
16 |
17 | message PaymentParams {
18 | string partySrc = 1;
19 | string partyDst = 2;
20 | int32 amount = 3;
21 | }
22 |
23 |
24 | //
25 | // Available RPC functions exported by this interface
26 | //
27 | // void MakePayment(PaymentParams) -> org.hyperledger.chaincode.example02/txn/1
28 | // void DeleteAccount(Entity) -> org.hyperledger.chaincode.example02/txn/2
29 | // BalanceResult CheckBalance(Entity) -> org.hyperledger.chaincode.example02/query/1
30 |
--------------------------------------------------------------------------------
/examples/helloworld/chaincode.yaml:
--------------------------------------------------------------------------------
1 | # ----------------------------------
2 | # chaincode "hello world"
3 | # ----------------------------------
4 | #
5 | # Copyright Greg Haskins All Rights Reserved
6 | #
7 | # SPDX-License-Identifier: Apache-2.0
8 | #
9 |
10 | Schema: 1
11 | Name: org.hyperledger.chaincode.helloworld
12 | Version: 0.1-SNAPSHOT
13 |
14 | Platform:
15 | Name: org.hyperledger.chaincode.golang
16 | Version: 1
17 |
18 | Provides: [self]
19 |
--------------------------------------------------------------------------------
/examples/helloworld/src/chaincode/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Greg Haskins 2017. All Rights Reserved.
3 |
4 | SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package main
8 |
9 | import (
10 | "fmt"
11 |
12 | "hyperledger/cci/appinit"
13 | "hyperledger/ccs"
14 |
15 | "org/hyperledger/chaincode/helloworld"
16 |
17 | "github.com/hyperledger/fabric/core/chaincode/shim"
18 | )
19 |
20 | type ChaincodeExample struct {
21 | }
22 |
23 | func (t *ChaincodeExample) Init(stub shim.ChaincodeStubInterface, param *appinit.Init) error {
24 |
25 | return nil
26 | }
27 |
28 | func main() {
29 | self := &ChaincodeExample{}
30 | hello := &helloworld.Interface{}
31 | interfaces := ccs.Interfaces{
32 | "org.hyperledger.chaincode.helloworld": hello,
33 | "appinit": self,
34 | }
35 |
36 | err := ccs.Start(interfaces) // Our one instance implements both Transactions and Queries interfaces
37 | if err != nil {
38 | fmt.Printf("Error starting example chaincode: %s", err)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/examples/helloworld/src/interfaces/appinit.cci:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | message Init {
8 | }
9 |
--------------------------------------------------------------------------------
/examples/helloworld/src/interfaces/org.hyperledger.chaincode.helloworld.cci:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | functions {
8 | string Hello(string) = 1;
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/examples/helloworld/src/org/hyperledger/chaincode/helloworld/core.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Greg Haskins 2017. All Rights Reserved.
3 |
4 | SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | package helloworld
8 |
9 | import (
10 | "fmt"
11 |
12 | "github.com/hyperledger/fabric/core/chaincode/shim"
13 | )
14 |
15 | type Interface struct {
16 | }
17 |
18 | func (t *Interface) Hello(stub shim.ChaincodeStubInterface, name *string) (string, error) {
19 |
20 | return fmt.Sprintf("Hello, %s", *name), nil
21 | }
22 |
--------------------------------------------------------------------------------
/examples/invoker/chaincode.yaml:
--------------------------------------------------------------------------------
1 |
2 | # -----------------------------------------------------------------------
3 | # chaincode invoker
4 | # -----------------------------------------------------------------------
5 | #
6 | #
7 | # Copyright Greg Haskins All Rights Reserved
8 | #
9 | # SPDX-License-Identifier: Apache-2.0
10 | #
11 | # This example demonstrates chaincode to chaincode invoke. This example
12 | # consumes the services of our example02 chaincode
13 | #
14 |
15 | Schema: 1
16 | Name: org.hyperledger.chaincode.example.invoker
17 | Version: 0.1-SNAPSHOT
18 |
19 | Platform:
20 | Name: org.hyperledger.chaincode.golang
21 | Version: 1
22 |
23 | Provides: [org.hyperledger.chaincode.example02]
24 | Consumes: [org.hyperledger.chaincode.example02]
25 |
--------------------------------------------------------------------------------
/examples/invoker/src/chaincode/chaincode.go:
--------------------------------------------------------------------------------
1 | /*
2 | SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | package main
6 |
7 | import (
8 | "fmt"
9 |
10 | "hyperledger/cci/appinit"
11 | "hyperledger/cci/org/hyperledger/chaincode/example02"
12 | "hyperledger/ccs"
13 |
14 | "github.com/hyperledger/fabric/core/chaincode/shim"
15 | )
16 |
17 | type ChaincodeExample struct {
18 | }
19 |
20 | // Called to initialize the chaincode
21 | func (t *ChaincodeExample) Init(stub shim.ChaincodeStubInterface, param *appinit.Init) error {
22 |
23 | var err error
24 |
25 | // Write the state to the ledger
26 | err = stub.PutState("ProxyAddress", []byte(param.Address))
27 | if err != nil {
28 | return err
29 | }
30 |
31 | return nil
32 | }
33 |
34 | // Transaction makes payment of X units from A to B
35 | func (t *ChaincodeExample) MakePayment(stub shim.ChaincodeStubInterface, param *example02.PaymentParams) error {
36 |
37 | var err error
38 |
39 | // Get the state from the ledger
40 | addr, err := stub.GetState("ProxyAddress")
41 | if err != nil {
42 | return err
43 | }
44 |
45 | return example02.MakePayment(stub, string(addr), param)
46 | }
47 |
48 | // Deletes an entity from state
49 | func (t *ChaincodeExample) DeleteAccount(stub shim.ChaincodeStubInterface, param *example02.Entity) error {
50 |
51 | var err error
52 |
53 | // Get the state from the ledger
54 | addr, err := stub.GetState("ProxyAddress")
55 | if err != nil {
56 | return err
57 | }
58 |
59 | return example02.DeleteAccount(stub, string(addr), param)
60 | }
61 |
62 | // Query callback representing the query of a chaincode
63 | func (t *ChaincodeExample) CheckBalance(stub shim.ChaincodeStubInterface, param *example02.Entity) (*example02.BalanceResult, error) {
64 |
65 | var err error
66 |
67 | // Get the state from the ledger
68 | addr, err := stub.GetState("ProxyAddress")
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | return example02.CheckBalance(stub, string(addr), param)
74 | }
75 |
76 | func main() {
77 | self := &ChaincodeExample{}
78 | interfaces := ccs.Interfaces{
79 | "org.hyperledger.chaincode.example02": self,
80 | "appinit": self,
81 | }
82 | err := ccs.Start(interfaces) // Our one instance implements both Transactions and Queries interfaces
83 | if err != nil {
84 | fmt.Printf("Error starting example chaincode: %s", err)
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/examples/invoker/src/interfaces/appinit.cci:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Copyright Greg Haskins All Rights Reserved
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 | #
7 | message Init {
8 | string address = 1;
9 | }
10 |
--------------------------------------------------------------------------------
/examples/invoker/src/interfaces/org.hyperledger.chaincode.example02.cci:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | message PaymentParams {
8 | string partySrc = 1;
9 | string partyDst = 2;
10 | int32 amount = 3;
11 | }
12 |
13 | message Entity {
14 | string id = 1;
15 | }
16 |
17 | message BalanceResult {
18 | int32 balance = 1;
19 | }
20 |
21 | functions {
22 | void MakePayment(PaymentParams) = 1;
23 | void DeleteAccount(Entity) = 2;
24 | BalanceResult CheckBalance(Entity) = 3;
25 | }
26 |
--------------------------------------------------------------------------------
/examples/parameterless/chaincode.yaml:
--------------------------------------------------------------------------------
1 | # ----------------------------------
2 | # chaincode example "parameterless"
3 | # ----------------------------------
4 | #
5 | # Copyright (C) 2016 - Hyperledger
6 | # All rights reserved
7 | #
8 |
9 | Schema: 1
10 | Name: org.hyperledger.chaincode.example.parameterless
11 | Version: 0.1-SNAPSHOT
12 |
13 | Platform:
14 | Name: org.hyperledger.chaincode.golang
15 | Version: 1
16 |
17 | Provides: [self]
18 | Consumes: [org.hyperledger.chaincode.example.parameterless]
19 |
--------------------------------------------------------------------------------
/examples/parameterless/src/chaincode/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | package main
6 |
7 | import (
8 | "fmt"
9 |
10 | "hyperledger/cci/appinit"
11 | app "hyperledger/cci/org/hyperledger/chaincode/example/parameterless"
12 | "hyperledger/ccs"
13 |
14 | "github.com/hyperledger/fabric/core/chaincode/shim"
15 | )
16 |
17 | type ChaincodeExample struct {
18 | }
19 |
20 | // Called to initialize the chaincode
21 | func (t *ChaincodeExample) Init(stub shim.ChaincodeStubInterface, param *appinit.Init) error {
22 |
23 | return nil
24 | }
25 |
26 | func (t *ChaincodeExample) TestParameterless(stub shim.ChaincodeStubInterface) (*app.MyReturnType, error) {
27 | return nil, nil
28 | }
29 |
30 | func main() {
31 | self := &ChaincodeExample{}
32 | interfaces := ccs.Interfaces{
33 | "org.hyperledger.chaincode.example.parameterless": self,
34 | "appinit": self,
35 | }
36 |
37 | err := ccs.Start(interfaces) // Our one instance implements both Transactions and Queries interfaces
38 | if err != nil {
39 | fmt.Printf("Error starting example chaincode: %s", err)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/parameterless/src/interfaces/appinit.cci:
--------------------------------------------------------------------------------
1 | message Init {
2 | }
3 |
--------------------------------------------------------------------------------
/examples/parameterless/src/interfaces/org.hyperledger.chaincode.example.parameterless.cci:
--------------------------------------------------------------------------------
1 |
2 | message MyReturnType {
3 | string foo = 1;
4 | }
5 |
6 | functions {
7 | MyReturnType TestParameterless() = 1;
8 | }
9 |
--------------------------------------------------------------------------------
/examples/sample_syscc/chaincode.yaml:
--------------------------------------------------------------------------------
1 |
2 | # ----------------------------------
3 | # chaincode example02
4 | # ----------------------------------
5 | #
6 | #
7 | # Copyright Greg Haskins All Rights Reserved
8 | #
9 | # SPDX-License-Identifier: Apache-2.0
10 | #
11 | #
12 |
13 | Schema: 1
14 | Name: org.hyperledger.chaincode.system.sample
15 | Version: 0.1-SNAPSHOT
16 |
17 | Platform:
18 | Name: org.hyperledger.chaincode.system
19 | Version: 1
20 |
21 | Provides: [self] # 'self' is a keyword that means there should be $name.cci (e.g. org.hyperledger.chaincode.system.sample.cci)
22 |
--------------------------------------------------------------------------------
/examples/sample_syscc/interfaces/appinit.cci:
--------------------------------------------------------------------------------
1 |
2 | message Party {
3 | string entity = 1;
4 | int32 value = 2;
5 | }
6 |
7 | message Init {
8 | Party partyA = 1;
9 | Party partyB = 2;
10 | }
11 |
--------------------------------------------------------------------------------
/examples/sample_syscc/interfaces/org.hyperledger.chaincode.system.sample.cci:
--------------------------------------------------------------------------------
1 |
2 | message PaymentParams {
3 | string partySrc = 1;
4 | string partyDst = 2;
5 | int32 amount = 3;
6 | }
7 |
8 | message Entity {
9 | string id = 1;
10 | }
11 |
12 | message BalanceResult {
13 | int32 balance = 1;
14 | }
15 |
16 | functions {
17 | void MakePayment(PaymentParams) = 1;
18 | void DeleteAccount(Entity) = 2;
19 | BalanceResult CheckBalance(Entity) = 3;
20 | }
21 |
--------------------------------------------------------------------------------
/examples/sample_syscc/sample_syscc.go:
--------------------------------------------------------------------------------
1 | /*
2 | SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | package sample_syscc
6 |
7 | import (
8 | "errors"
9 | "github.com/hyperledger/fabric/core/chaincode/shim"
10 | )
11 |
12 | // SampleSysCC example simple Chaincode implementation
13 | type SampleSysCC struct {
14 | }
15 |
16 | func (t *SampleSysCC) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
17 | var key, val string // Entities
18 |
19 | if len(args) != 2 {
20 | return nil, errors.New("need 2 args (key and a value).")
21 | }
22 |
23 | // Initialize the chaincode
24 | key = args[0]
25 | val = args[1]
26 | // Write the state to the ledger
27 | err := stub.PutState(key, []byte(val))
28 | if err != nil {
29 | return nil, err
30 | }
31 |
32 | return nil, nil
33 | }
34 |
35 | // Transaction makes payment of X units from A to B
36 | func (t *SampleSysCC) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
37 | var key, val string // Entities
38 |
39 | if len(args) != 2 {
40 | return nil, errors.New("need 2 args (key and a value).")
41 | }
42 |
43 | // Initialize the chaincode
44 | key = args[0]
45 | val = args[1]
46 |
47 | _, err := stub.GetState(key)
48 | if err != nil {
49 | jsonResp := "{\"Error\":\"Failed to get val for " + key + "\"}"
50 | return nil, errors.New(jsonResp)
51 | }
52 |
53 | // Write the state to the ledger
54 | err = stub.PutState(key, []byte(val))
55 | if err != nil {
56 | return nil, err
57 | }
58 |
59 | return nil, nil
60 | }
61 |
62 | // Query callback representing the query of a chaincode
63 | func (t *SampleSysCC) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
64 | if function != "getval" {
65 | return nil, errors.New("Invalid query function name. Expecting \"getval\"")
66 | }
67 | var key string // Entities
68 | var err error
69 |
70 | if len(args) != 1 {
71 | return nil, errors.New("Incorrect number of arguments. Expecting key to query")
72 | }
73 |
74 | key = args[0]
75 |
76 | // Get the state from the ledger
77 | valbytes, err := stub.GetState(key)
78 | if err != nil {
79 | jsonResp := "{\"Error\":\"Failed to get state for " + key + "\"}"
80 | return nil, errors.New(jsonResp)
81 | }
82 |
83 | if valbytes == nil {
84 | jsonResp := "{\"Error\":\"Nil val for " + key + "\"}"
85 | return nil, errors.New(jsonResp)
86 | }
87 |
88 | return valbytes, nil
89 | }
90 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright Greg Haskins All Rights Reserved
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | site_name: Hyperledger Fabric Chaintool
8 | site_url: http://fabric-chaintool.readthedocs.io
9 | theme: readthedocs
10 | repo_url: https://github.com/hyperledger/fabric-chaintool.git
11 | site_description: 'Welcome to the Hyperledger fabric chaintool documentation'
12 | strict: true
13 |
14 | pages:
15 | - Introduction: index.md
16 | - Getting Started: getting-started.md
17 | - Interface Definition Language: interface.md
18 | - Command Reference: command-reference.md
19 | - Application Development: application-development.md
20 | - Client Development: client-development.md
21 | - Chaincode Platforms:
22 | - org.hyperledger.chaincode.golang: platforms/golang.md
23 | - org.hyperledger.chaincode.system: platforms/system.md
24 | - Metadata: metadata.md
25 |
26 | markdown_extensions:
27 | - toc:
28 | permalink: true
29 | - admonition
30 | - extra
31 | - tables
32 | - toc
33 | - fenced_code
34 | - smarty
35 | - footnotes
36 |
37 | copyright:
Contributed to the Hyperledger Project under the Apache Software License 2.0
38 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | ;;
2 | ;; Copyright Greg Haskins All Rights Reserved
3 | ;;
4 | ;; SPDX-License-Identifier: Apache-2.0
5 | ;;
6 |
7 | (defproject chaintool "1.1.4-SNAPSHOT"
8 | :description "Hyperledger Fabric chaincode tool"
9 | :url "https://github.com/hyperledger/fabric-chaintool"
10 | :license {:name "Apache License"
11 | :url "http://www.apache.org/licenses/LICENSE-2.0.txt"}
12 | :min-lein-version "2.0.0"
13 | :lein-release {:deploy-via :shell :shell ["true"]}
14 | :javac-options ["-target" "1.8" "-source" "1.8"]
15 | :jvm-opts ["-server"]
16 | :java-source-paths ["src"]
17 | :plugins [[lein-bin "0.3.5"]
18 | [lein-licenses "0.2.1"]]
19 | :dependencies [[org.clojure/clojure "1.9.0"]
20 | [org.clojure/tools.cli "0.3.5"]
21 | [org.clojure/algo.generic "0.1.2"]
22 | [org.clojure/data.codec "0.1.1"]
23 | [instaparse "1.4.8"]
24 | [clojure-tools "1.1.3"]
25 | [org.antlr/ST4 "4.0.8"]
26 | [me.raynes/conch "0.8.0"]
27 | [me.raynes/fs "1.4.6"]
28 | [org.clojars.ghaskins/protobuf "3.4.0-1"]
29 | [commons-io/commons-io "2.6"]
30 | [org.tukaani/xz "1.8"]
31 | [org.apache.commons/commons-compress "1.16.1"]
32 | [com.github.jponge/lzma-java "1.3"]
33 | [pandect "0.5.4"]
34 | [doric "0.9.0"]
35 | [circleci/clj-yaml "0.5.6"]
36 | [slingshot "0.12.2"]
37 | [clj-http "3.8.0"]
38 | [cheshire "5.8.0"]]
39 | :main ^:skip-aot chaintool.core
40 | :bin {:name "chaintool"
41 | :bin-path "target"
42 | :bootclasspath true}
43 | :target-path "target/%s"
44 |
45 | ;; nREPL by default starts in the :main namespace, we want to start in `user`
46 | ;; because that's where our development helper functions like (run) and
47 | ;; (browser-repl) live.
48 | :repl-options {:init-ns user}
49 |
50 | :profiles {:dev {:dependencies [[org.clojure/tools.nrepl "0.2.13"]
51 | [org.clojure/tools.namespace "0.2.11"]]
52 | :plugins [[cider/cider-nrepl "0.15.1"]]
53 | :source-paths ["dev"]}
54 | :uberjar {:aot :all}})
55 |
--------------------------------------------------------------------------------
/resources/generators/proto.stg:
--------------------------------------------------------------------------------
1 | emitfield(field) ::= " = ;"
2 |
3 | emitmsg(msg) ::=
4 | <<
5 | message {
6 |
7 | }
8 | >>
9 |
10 | emitenum(enum) ::=
11 | <<
12 | enum {
13 | }; separator="\n">
14 | }
15 | >>
16 |
17 | emitoneof(oneof) ::=
18 | <<
19 | oneof {
20 | }; separator="\n">
21 | }
22 | >>
23 |
24 | emitdef(def) ::=
25 | <<
26 |
27 |
28 |
29 |
30 | >>
31 |
32 | emitdefs(defs) ::= "}; separator=\"\n\">"
33 |
34 | protobuf(package, definitions, functions) ::=
35 | <<
36 | //
37 | // Generated by chaintool. DO NOT EDIT!!
38 | //
39 |
40 | syntax = "proto3";
41 |
42 | package ;
43 |
44 |
45 |
46 |
47 | //
48 | // Available RPC functions exported by this interface
49 | //
50 |
51 | () -> }; separator="\n">
52 |
53 | >>
54 |
--------------------------------------------------------------------------------
/resources/metadata/org.hyperledger.chaintool.meta.cci:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Copyright Greg Haskins All Rights Reserved
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 | #
7 | message InterfaceDescriptor {
8 | string name = 1;
9 | bytes data = 2;
10 | }
11 |
12 | message Interfaces {
13 | repeated InterfaceDescriptor descriptors = 1;
14 | }
15 |
16 | message GetInterfacesParams {
17 | bool IncludeContent = 1;
18 | }
19 |
20 | message GetInterfaceParams {
21 | string name = 1;
22 | }
23 |
24 | message GetFactsParams {
25 | }
26 |
27 | message Facts {
28 | message Fact {
29 | string name = 1;
30 | string value = 2;
31 | }
32 |
33 | repeated Fact facts = 1;
34 | }
35 |
36 | functions {
37 | Interfaces GetInterfaces(GetInterfacesParams) = 1;
38 | InterfaceDescriptor GetInterface(GetInterfaceParams) = 2;
39 | Facts GetFacts(GetFactsParams) = 3;
40 | }
41 |
--------------------------------------------------------------------------------
/resources/parsers/interface/grammar.bnf:
--------------------------------------------------------------------------------
1 | interface ::= ( message | enum )* functions?
2 |
3 | message ::= <"message"> ident messageBody
4 |
5 | enum ::= <"enum"> ident <"{"> ( enumField | <";"> )* <"}">
6 |
7 | enumField ::= enumName <"="> enumValue <";">
8 | ::= ident
9 | ::= intLit
10 |
11 | functions ::= <"functions"> functionblock
12 |
13 | ::= <"{"> function* <"}">
14 | function ::= rettype functionName <"("> param? <")"> <"="> index <";">
15 | functionName := ident
16 | rettype ::= ident
17 | param ::= ident
18 |
19 | optionBody ::= ident ( "." ident )* "=" constant
20 |
21 | ::= <"{"> ( field | enum | message | oneof )* <"}">
22 |
23 | field ::= modifier? type fieldName <"="> index ( <"["> fieldOption ( <","> fieldOption )* <"]"> )? <";">
24 |
25 | fieldName ::= ident
26 | fieldOption ::= optionBody | "default" "=" constant
27 |
28 | modifier ::= "required" | "repeated"
29 |
30 | type ::= scalar / userType / map / oneof
31 |
32 | scalar ::= "double" | "float" | "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string" | "bytes"
33 |
34 | userType ::= #"[A-Za-z_\.]*"
35 |
36 | map = <"map"> <"<"> keyType <","> type <">">
37 | keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" |
38 | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string"
39 |
40 | oneof ::= <"oneof"> ident <"{"> (field | <";">)* <"}">
41 |
42 | constant ::= ident | intLit | floatLit | strLit | boolLit
43 |
44 | ::= #"[A-Za-z_][\w_]*"
45 |
46 | camelIdent ::= #"[A-Z][\w_]*"
47 |
48 | index ::= intLit
49 |
50 | ::= decInt | hexInt | octInt
51 |
52 | ::= #"\d+"
53 |
54 | ::= #"0[xX]([A-Fa-f0-9])+"
55 |
56 | ::= #"0[0-7]+"
57 |
58 | ::= #"\d+(\.\d+)?([Ee][\+-]?\d+)?"
59 |
60 | ::= "true" | "false"
61 |
62 | ::= quote ( hexEscape | octEscape | charEscape )* quote
63 |
64 | ::= #"[\"']"
65 |
66 | ::= #"\\[Xx][A-Fa-f0-9]{1,2}"
67 |
68 | ::= #"\\0?[0-7]{1,3}"
69 |
70 | ::= #"\\[abfnrtv\\\?'\"]"
71 |
--------------------------------------------------------------------------------
/resources/parsers/interface/skip.bnf:
--------------------------------------------------------------------------------
1 | skipper ::= (whitespace | blankline | ( wlcomment / comment))*
2 |
3 | whitespace ::= #"[ \t]"
4 | blankline ::= #"^\n"
5 | wlcomment ::= #'^' comment
6 | comment ::= ('//' | '#') (!'\n' #'.')* '\n'
7 |
--------------------------------------------------------------------------------
/resources/parsers/proto/grammar.bnf:
--------------------------------------------------------------------------------
1 | proto ::= syntax? package? ( message | enum )*
2 |
3 | syntax ::= <"syntax"> <"="> <"\""> ident <"\""><";">
4 | package ::= <"package"> packageName <";">
5 |
6 | packageName ::= #"[A-Za-z_.]*"
7 |
8 | message ::= <"message"> ident messageBody
9 |
10 | enum ::= <"enum"> ident <"{"> ( enumField | <";"> )* <"}">
11 |
12 | enumField ::= enumName <"="> enumValue <";">
13 | ::= ident
14 | ::= intLit
15 |
16 | optionBody ::= ident ( "." ident )* "=" constant
17 |
18 | ::= <"{"> ( field | enum | message | oneof )* <"}">
19 |
20 | field ::= modifier? type fieldName <"="> index ( <"["> fieldOption ( <","> fieldOption )* <"]"> )? <";">
21 |
22 | fieldName ::= ident
23 | fieldOption ::= optionBody | "default" "=" constant
24 |
25 | modifier ::= "required" | "repeated"
26 |
27 | type ::= scalar / userType / map / oneof
28 |
29 | scalar ::= "double" | "float" | "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string" | "bytes"
30 |
31 | userType ::= ( "."? ident )+
32 |
33 | map = <"map"> <"<"> keyType <","> type <">">
34 | keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" |
35 | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string"
36 |
37 | oneof ::= <"oneof"> ident <"{"> (field | <";">)* <"}">
38 |
39 | constant ::= ident | intLit | floatLit | strLit | boolLit
40 |
41 | ::= #"[A-Za-z_][\w_]*"
42 |
43 | camelIdent ::= #"[A-Z][\w_]*"
44 |
45 | index ::= intLit
46 |
47 | ::= decInt | hexInt | octInt
48 |
49 | ::= #"\d+"
50 |
51 | ::= #"0[xX]([A-Fa-f0-9])+"
52 |
53 | ::= #"0[0-7]+"
54 |
55 | ::= #"\d+(\.\d+)?([Ee][\+-]?\d+)?"
56 |
57 | ::= "true" | "false"
58 |
59 | ::= quote ( hexEscape | octEscape | charEscape )* quote
60 |
61 | ::= #"[\"']"
62 |
63 | ::= #"\\[Xx][A-Fa-f0-9]{1,2}"
64 |
65 | ::= #"\\0?[0-7]{1,3}"
66 |
67 | ::= #"\\[abfnrtv\\\?'\"]"
68 |
--------------------------------------------------------------------------------
/resources/parsers/proto/skip.bnf:
--------------------------------------------------------------------------------
1 | skipper ::= (whitespace | blankline | ( wlcomment / comment))*
2 |
3 | whitespace ::= #"[ \t]"
4 | blankline ::= #"^\n"
5 | wlcomment ::= #'^' comment
6 | comment ::= ('//' | '#') (!'\n' #'.')* '\n'
7 |
--------------------------------------------------------------------------------
/resources/proto/car.proto:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright London Stock Exchange Group 2016 All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 |
18 | /*
19 | *************************************************************************************
20 |
21 | We create a new archive format called CAR (chaincode archive) to package up
22 | chaincode assets. Our first approach was to reuse an existing archive format/tooling
23 | (e.g. tar, zip, etc). However, most had problems with determinisim. For instance,
24 | tar injects things like UIDs and timestamps into the binary, which could result
25 | in a different binary each time regardless of code content.
26 |
27 | The "ar" tool from binutils showed some promise with explicit support for determinism,
28 | but its focus on elf containers seemed inappropriate. In the end, we realized it
29 | might be more straightforward to leverage our existing investment in protobufs and
30 | build our own custom format. It's not all that complicated anyway (famous last words).
31 |
32 | The current implementation is somewhat naive in that it assumes that the compressed
33 | contents of the archive will have no problem fitting in memory and/or a single
34 | protobuf object (defaults to 64MB max, I think). This is ok. For one, chaincode
35 | packages by definition should strive to be as small as possible since they
36 | need to be distributed around and persisted on the ledger. We certainly don't want to
37 | encourage anyone to submit really huge applications by making it easy to package one
38 | up ;). If this ever changes, the fundamental nature of protobufs should allow us
39 | to be creative in enhancing the capabilities without breaking compatibility.
40 |
41 | ---- Schema -----
42 |
43 | current definition {:magic "org.hyperledger.chaincode-archive" :version 1}
44 |
45 | A given archive file consists of two primary protobuf objects:
46 |
47 | [[delim] CompatibilityHeader, [delim] Archive]
48 |
49 | that are written with the java .writeDelimitedTo() (https://goo.gl/8NeMkT) function.
50 | The delimimter is a simple size indicator, the specifications of which are left
51 | as an exercise for the reader. The rest of the specification should be
52 | understandable to someone fluent in protobuf definitions, as per below.
53 |
54 | A few notes:
55 |
56 | 1) Generally speaking, for a given {:magic :version} tuple, the
57 | CompatibilityHeader should never, ever, ever be modified in a way that breaks
58 | backwards/forward compatibility. It is, however, ok to extend it using standard
59 | protobuf techniques should that ever be necessary. Most enhancements should be
60 | done via the "features" facility. For example:
61 |
62 | features = ["org.hyperledger.car.enhancement23", "com.acme.gizmo.awesome"]
63 |
64 | may indicate that certain features are present. Components that understand
65 | what that means may react to the presence of the feature flag. Those that
66 | do not should be able to safely ignore it (generally relying on protobuf
67 | techniques to avoid incongruent structures)
68 | 2) If breaking compatibility is unvoidable, you _must_ modify either one or both
69 | of the {:magic :version} tuple. Changing either one is a statment of gross
70 | incompatibility with orthogonal version tuples. This is generally only done
71 | in extreme circumstances as an alternative to leaving software with no
72 | deterministic method to detect a problem.
73 | 3) There is an intentional level of indirection between Archive and Payload to
74 | facilitate ease in generating a comprehensive signature. Achive.payload is
75 | expected to be the raw binary serialized form of Achive::Payload.
76 | 4) The top-level Archive object should generally strive to remain as lightweight
77 | as possible to encapsulate as many fields as possible under the signature
78 | algorithm.
79 |
80 | ***************************************************************************************
81 | */
82 |
83 | syntax = "proto2";
84 | package chaintool.car.abi;
85 |
86 | message CompatibilityHeader {
87 | required string magic = 1;
88 | required int32 version = 2;
89 | repeated string features = 3;
90 | }
91 |
92 | message Archive {
93 | message Signature {
94 | enum Type {
95 | NONE = 1;
96 | RSA = 2;
97 | }
98 |
99 | optional Type type = 1;
100 | optional string description = 2;
101 | optional bytes data = 3;
102 | }
103 |
104 | message Payload {
105 | message Compression {
106 | enum Type {
107 | NONE = 1;
108 | GZIP = 2;
109 | LZMA = 3;
110 | BZIP2 = 4;
111 | XZ = 5;
112 | }
113 |
114 | optional Type type = 1 [default = NONE];
115 | optional string description = 2;
116 | }
117 |
118 | message Entries {
119 | optional string path = 1;
120 | optional uint64 size = 2;
121 | optional string sha1 = 3;
122 | optional bytes data = 16;
123 | }
124 |
125 | optional Compression compression = 1;
126 | repeated Entries entries = 16;
127 | }
128 |
129 | optional Signature signature = 1;
130 | optional bytes payload = 2;
131 | }
132 |
--------------------------------------------------------------------------------
/scripts/changelog.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # Copyright IBM Corp All Rights Reserved
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 | #
7 |
8 | if [ "$#" -ne 2 ]; then
9 | echo "Prepends a changelog into the current CHANGELOG.md at the root of the project"
10 | echo "Note: must be run from root directory of repository clone"
11 | echo "Usage: ./scripts/changelog.sh "
12 | exit 1
13 | fi
14 |
15 | echo "## $2\n$(date)" >> CHANGELOG.new
16 | echo "" >> CHANGELOG.new
17 | git log $1..HEAD --oneline | grep -v Merge | sed -e "s/\[\(FAB-[0-9]*\)\]/\[\1\](https:\/\/jira.hyperledger.org\/browse\/\1\)/" -e "s/ \(FAB-[0-9]*\)/ \[\1\](https:\/\/jira.hyperledger.org\/browse\/\1\)/" -e "s/\([0-9|a-z]*\)/* \[\1\](https:\/\/github.com\/hyperledger\/fabric\/commit\/\1)/" >> CHANGELOG.new
18 | echo "" >> CHANGELOG.new
19 | cat CHANGELOG.md >> CHANGELOG.new
20 | mv -f CHANGELOG.new CHANGELOG.md
21 |
--------------------------------------------------------------------------------
/src/chaintool/ast.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.ast
16 | (:require [clojure.zip :as zip])
17 | (:refer-clojure :exclude [find]))
18 |
19 | ;;-----------------------------------------------------------------
20 | ;; find a specific element in the AST
21 | ;;-----------------------------------------------------------------
22 | (defn find [term ast]
23 | (loop [loc ast]
24 | (cond
25 |
26 | (or (nil? loc) (zip/end? loc))
27 | nil
28 |
29 | (= (zip/node loc) term)
30 | (zip/up loc)
31 |
32 | :else
33 | (recur (zip/next loc)))))
34 |
--------------------------------------------------------------------------------
/src/chaintool/build/core.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.build.core
15 | (:require [chaintool.platforms.core :as platforms.core]
16 | [chaintool.platforms.api :as platforms.api])
17 | (:refer-clojure :exclude [compile]))
18 |
19 |
20 | (defn- run [fcn {:keys [config] :as params}]
21 | (when-let [platform (platforms.core/find config)]
22 | (fcn platform params)))
23 |
24 | ;; generate platform output (shim, protobufs, etc)
25 | (defn compile [params]
26 | (run platforms.api/build params))
27 |
28 | ;; display environment variables used for build
29 | (defn env [params]
30 | (run platforms.api/env params))
31 |
--------------------------------------------------------------------------------
/src/chaintool/car/ls.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.car.ls
16 | (:require [chaintool.car.read :as car]
17 | [clojure.java.io :as io]
18 | [doric.core :as doric]
19 | [pandect.algo.sha3-512 :refer :all]))
20 |
21 | (defn platform-version [config]
22 | (str (->> config :Platform :Name) " version " (->> config :Platform :Version)))
23 |
24 | (defn ls [file]
25 | (let [{:keys [payload config]} (with-open [is (io/input-stream file)] (car/read is))
26 | entries (:entries payload)]
27 |
28 | (println (doric/table [{:name :size} {:name :sha1 :title "SHA1"} {:name :path}] entries))
29 | (println "Platform: " (platform-version config))
30 | (println "Digital Signature: none")
31 | (println "Raw Data Size: " (->> entries (map :size) (reduce +)) "bytes")
32 | (println "Archive Size: " (.length file) "bytes")
33 | (println "Compression Alg: " (get-in payload [:compression :description]))
34 | (println "Chaincode SHA3: " (sha3-512 file))))
35 |
--------------------------------------------------------------------------------
/src/chaintool/car/read.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.car.read
16 | (:require [flatland.protobuf.core :as fl]
17 | [chaintool.util :as util]
18 | [chaintool.car.types :refer :all]
19 | [chaintool.codecs :as codecs]
20 | [chaintool.config.parser :as config.parser]
21 | [chaintool.config.util :as config.util]
22 | [pandect.algo.sha1 :refer :all])
23 | (:refer-clojure :exclude [read]))
24 |
25 | ;;--------------------------------------------------------------------------------------
26 | ;; read-protobuf - reads a single protobuf message from a delimited stream
27 | ;;
28 | ;; our protobuf file consists of two primary message types, delimited by a size.
29 | ;; (fl/protobuf-seq) is designed to return an infinite lazy sequence of one type
30 | ;; so we need to feed this through (first) to extract only one.
31 | ;;--------------------------------------------------------------------------------------
32 | (defn read-protobuf [t is] (->> is (fl/protobuf-seq t) first))
33 |
34 | ;;--------------------------------------------------------------------------------------
35 | ;; read-XX - read one instance of a specific type of protobuf message [Header|Archive]
36 | ;;--------------------------------------------------------------------------------------
37 | (defn read-header [is] (read-protobuf Header is))
38 | (defn read-archive [is] (read-protobuf Archive is))
39 |
40 | ;;--------------------------------------------------------------------------------------
41 | ;; make-input-stream - factory function for creating an input-stream for a specific entry
42 | ;;
43 | ;; We install the necessary decompressor such that the output of this stream represents
44 | ;; raw, uncompressed original data
45 | ;;--------------------------------------------------------------------------------------
46 | (defn make-input-stream [type entry]
47 | (let [is (->> entry :data .newInput)]
48 | (codecs/decompressor type is)))
49 |
50 | ;;--------------------------------------------------------------------------------------
51 | ;; import-header - imports and validates a Header object from the input stream
52 | ;;
53 | ;; evaluates to the parsed header if successful, or throws an exception otherwise
54 | ;;--------------------------------------------------------------------------------------
55 | (defn import-header [is]
56 | (if-let [header (read-header is)]
57 | (let [compat (select-keys header [:magic :version])]
58 | (if (= compat CompatVersion)
59 | (:features header)
60 | (util/abort -1 (str "Incompatible header detected (expected: " CompatVersion " got: " compat ")"))))
61 | (util/abort -1 (str "Failed to read archive header"))))
62 |
63 | ;;--------------------------------------------------------------------------------------
64 | ;; import-archive - imports an Archive object from the input stream
65 | ;;--------------------------------------------------------------------------------------
66 | (defn import-archive [is]
67 | (read-archive is)) ;; FIXME - check digitial signature
68 |
69 | ;;--------------------------------------------------------------------------------------
70 | ;; import-entry - validates an entry object
71 | ;;
72 | ;; returns the proper input-stream-factory when sucessful, or throws an exception otherwise
73 | ;;--------------------------------------------------------------------------------------
74 | (defn import-entry [compression entry]
75 | (let [type (:description compression)
76 | factory #(make-input-stream type entry)]
77 |
78 | ;; verify the SHA1
79 | (with-open [is (factory)]
80 | (let [sha (sha1 is)]
81 | (when (not= sha (:sha1 entry))
82 | (util/abort -1 (str (:path entry) ": hash verification failure (expected: " (:sha1 entry) ", got: " sha ")")))))
83 |
84 | ;; and inject our stream factory
85 | {:entry entry :input-stream-factory factory}))
86 |
87 | ;;--------------------------------------------------------------------------------------
88 | ;; import-payload - imports a Payload object from Archive::Payload field
89 | ;;
90 | ;; We separate Archive from Payload to delineate signature boundaries. Everything within
91 | ;; Payload is expected to be optionally digitally signed (and thus verified upon import)
92 | ;;--------------------------------------------------------------------------------------
93 | (defn import-payload [archive] (->> archive :payload .newInput (fl/protobuf-load-stream Payload)))
94 |
95 | ;;--------------------------------------------------------------------------------------
96 | ;; synth-index - synthesize an index of entries, keyed by :path
97 | ;;
98 | ;; Takes a payload object and constructs a map of entries, keyed by their path. Each
99 | ;; entry is fully verified and processed (such as attaching an input-stream filter)
100 | ;;--------------------------------------------------------------------------------------
101 | (defn synth-index [payload]
102 | (let [compression (:compression payload)]
103 | (->> (:entries payload) (map #(vector (:path %) (import-entry compression %))) (into {}))))
104 |
105 | ;;--------------------------------------------------------------------------------------
106 | ;; entry-stream - instantiate an input-stream from the factory
107 | ;;
108 | ;; This allows a caller to obtain a simple input-stream interface to our entries where
109 | ;; all the details such as compression are already factored in. Therefore, this stream
110 | ;; is suitable to any number of tasks such as interpreting results, verifying contents,
111 | ;; or writing data to files
112 | ;;--------------------------------------------------------------------------------------
113 | (defn entry-stream [entry]
114 | (let [factory (:input-stream-factory entry)]
115 | (factory)))
116 |
117 | (defn read [is]
118 | (let [features (import-header is)
119 | archive (import-archive is)
120 | payload (import-payload archive)
121 | index (synth-index payload)]
122 |
123 | (with-open [config-stream (->> config.util/configname index entry-stream)]
124 | (let [config (->> config-stream slurp config.parser/from-string)]
125 | {:features features :payload payload :index index :config config}))))
126 |
--------------------------------------------------------------------------------
/src/chaintool/car/types.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.car.types
15 | (:import [chaintool.car.abi
16 | Car$CompatibilityHeader
17 | Car$Archive
18 | Car$Archive$Signature
19 | Car$Archive$Payload
20 | Car$Archive$Payload$Compression
21 | Car$Archive$Payload$Entries])
22 | (:require [flatland.protobuf.core :as fl]))
23 |
24 | (def Header (fl/protodef Car$CompatibilityHeader))
25 | (def Archive (fl/protodef Car$Archive))
26 | (def Signature (fl/protodef Car$Archive$Signature))
27 | (def Payload (fl/protodef Car$Archive$Payload))
28 | (def Compression (fl/protodef Car$Archive$Payload$Compression))
29 | (def Entries (fl/protodef Car$Archive$Payload$Entries))
30 |
31 | (def CompatVersion {:magic "org.hyperledger.chaincode-archive" :version 1})
32 |
--------------------------------------------------------------------------------
/src/chaintool/car/unpack.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.car.unpack
16 | (:require [clojure.java.io :as io]
17 | [chaintool.car.read :as car.read]))
18 |
19 | ;;--------------------------------------------------------------------------------------
20 | ;; unpack - given a (pre-read) index of entries and an outputdir, unpack each element
21 | ;;--------------------------------------------------------------------------------------
22 | (defn unpack [index outputdir verbose]
23 | (dorun
24 | (for [[path item] index]
25 | (let [entry (:entry item)
26 | outputfile (io/file outputdir path)]
27 |
28 | ;; ensure our output path exists
29 | (io/make-parents outputfile)
30 |
31 | ;; walk each entry and stream it out to the filesystem
32 | (with-open [is (car.read/entry-stream item)
33 | os (io/output-stream outputfile)]
34 |
35 | ;; we optionally may report out status to stdout
36 | (when (= verbose :true)
37 | (println (:sha1 entry) (:path entry) (str "(" (:size entry) " bytes)")))
38 |
39 | ;; stream it out, pulling the input stream through any appropriate decompressor transparently
40 | (io/copy is os))))))
41 |
--------------------------------------------------------------------------------
/src/chaintool/car/write.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.car.write
16 | (:require [chaintool.car.types :refer :all]
17 | [chaintool.codecs :as codecs]
18 | [chaintool.util :as util]
19 | [clojure.java.io :as io]
20 | [clojure.string :as string]
21 | [flatland.protobuf.core :as fl]
22 | [pandect.algo.sha1 :refer :all])
23 | (:import (org.apache.commons.io.input TeeInputStream)
24 | (org.apache.commons.io.output ByteArrayOutputStream))
25 | (:refer-clojure :exclude [import]))
26 |
27 | ;;--------------------------------------------------------------------------------------
28 | ;; import - takes a file handle and returns a tuple containing [sha1 size data]
29 | ;;
30 | ;; sha1: a string containing the computed sha1 of the raw uncompressed file contents
31 | ;; size: the raw uncompressed size of the file as it existed on the filesystem
32 | ;; data: a byte-array containing the compressed binary data imported from the filesystem
33 | ;;--------------------------------------------------------------------------------------
34 | (defn import [file compressiontype]
35 | (let [os (ByteArrayOutputStream.)
36 | [sha size] (with-open [is (io/input-stream file) ;; FIXME - validate maximum file size supported
37 | compressor (codecs/compressor compressiontype os)
38 | tee (TeeInputStream. is compressor)]
39 | [(sha1 tee) (.length file)])] ;; FIXME - prefer to get the length from the stream
40 | [sha size (.toByteArray os)]))
41 |
42 | ;;--------------------------------------------------------------------------------------
43 | ;; buildentry - builds a protobuf "Entry" object based on the tuple as emitted by (convertfile)
44 | ;;--------------------------------------------------------------------------------------
45 | (defn buildentry [{:keys [path handle]} compressiontype]
46 | (let [[sha size payload] (import handle compressiontype)]
47 | (fl/protobuf Entries :path path :size size :sha1 sha :data payload)))
48 |
49 | ;;--------------------------------------------------------------------------------------
50 | ;; buildentries - builds a list of protobuf "Entry" objects based on an input list
51 | ;; of {handle path} tuples. The input file list is sorted by :path to ensure
52 | ;; deterministic results
53 | ;;--------------------------------------------------------------------------------------
54 | (defn buildentries [files compressiontype]
55 | (->> files
56 | (sort-by :path)
57 | (map #(buildentry % compressiontype))))
58 |
59 | ;;--------------------------------------------------------------------------------------
60 | ;; buildcompression - builds a protobuf "Compression" object based on the requested type
61 | ;; after validating that the type is a supported option.
62 | ;;--------------------------------------------------------------------------------------
63 | (defn buildcompression [type]
64 | (if (codecs/codec-types type)
65 | (fl/protobuf Compression :type (string/upper-case type) :description type)))
66 |
67 | (defn write [files compressiontype outputfile]
68 | (if-let [compression (buildcompression compressiontype)]
69 | (let [header (fl/protobuf Header :magic (:magic CompatVersion) :version (:version CompatVersion))
70 | entries (buildentries files compressiontype)
71 | payload (fl/protobuf Payload :compression compression :entries entries)
72 | archive (fl/protobuf Archive :payload (fl/protobuf-dump payload))]
73 |
74 | ;; ensure the path exists
75 | (io/make-parents outputfile)
76 |
77 | ;; emit our output
78 | (with-open [os (io/output-stream outputfile :truncate true)]
79 | (fl/protobuf-write os header archive)))
80 |
81 | ;; else
82 | (util/abort -1 (str "Unknown compression type: \"" compressiontype "\""))))
83 |
--------------------------------------------------------------------------------
/src/chaintool/codecs.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.codecs
16 | (:import (lzma.streams LzmaOutputStream$Builder)
17 | (org.apache.commons.compress.compressors.bzip2 BZip2CompressorInputStream
18 | BZip2CompressorOutputStream)
19 | (org.apache.commons.compress.compressors.gzip GzipCompressorInputStream
20 | GzipCompressorOutputStream
21 | GzipParameters)
22 | (org.apache.commons.compress.compressors.lzma LZMACompressorInputStream)
23 | (org.apache.commons.compress.compressors.xz XZCompressorInputStream
24 | XZCompressorOutputStream)
25 | (org.apache.commons.io.input ProxyInputStream)
26 | (org.apache.commons.io.output ProxyOutputStream)))
27 |
28 | ;;--------------------------------------------------------------------------------------
29 | ;; compression support
30 | ;;--------------------------------------------------------------------------------------
31 | (def codec-descriptors
32 | [{:name "none"
33 | :output #(ProxyOutputStream. %)
34 | :input #(ProxyInputStream. %)}
35 |
36 | {:name "gzip"
37 | :output #(let [params (GzipParameters.)] (.setCompressionLevel params 9) (GzipCompressorOutputStream. % params))
38 | :input #(GzipCompressorInputStream. %)}
39 |
40 | {:name "lzma"
41 | :output #(-> (LzmaOutputStream$Builder. %) .build)
42 | :input #(LZMACompressorInputStream. %)}
43 |
44 | {:name "bzip2"
45 | :output #(BZip2CompressorOutputStream. %)
46 | :input #(BZip2CompressorInputStream. %)}
47 |
48 | {:name "xz"
49 | :output #(XZCompressorOutputStream. % 6)
50 | :input #(XZCompressorInputStream. %)}])
51 |
52 | (def codec-types (->> codec-descriptors (map #(vector (:name %) %)) (into {})))
53 |
54 | (defn compressor [type os] ((->> type codec-types :output) os))
55 | (defn decompressor [type is] ((->> type codec-types :input) is))
56 |
--------------------------------------------------------------------------------
/src/chaintool/config/parser.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.config.parser
16 | (:require [chaintool.util :as util]
17 | [clj-yaml.core :as yaml]))
18 |
19 | (def supported-schema 1)
20 |
21 | (defn from-string [data]
22 | (let [config (yaml/parse-string data)
23 | schema (:Schema config)]
24 | (if (not= schema supported-schema)
25 | (util/abort -1 (str "Unsuported configuration schema (read:" schema " expected:" supported-schema ")"))
26 | config)))
27 |
28 | (defn from-file [file] (->> file slurp from-string))
29 |
--------------------------------------------------------------------------------
/src/chaintool/config/util.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.config.util
16 | (:require [chaintool.util :as util]
17 | [clojure.java.io :as io]
18 | [clojure.zip :as zip]
19 | [chaintool.config.parser :as config.parser])
20 | (:refer-clojure :exclude [load find]))
21 |
22 | (def configname "chaincode.yaml")
23 |
24 | (defn load [path]
25 | (let [file (io/file path configname)]
26 | (cond
27 |
28 | (not (.isFile file))
29 | (util/abort -1 (str (.getCanonicalPath file) " not found"))
30 |
31 | :else
32 | (config.parser/from-file file))))
33 |
34 | (defn load-from-options [options]
35 | (let [path (:path options)
36 | config (load path)]
37 | [path config]))
38 |
39 | (defn compositename [config]
40 | (let [name (:Name config)
41 | version (:Version config)]
42 | (str name "-" version)))
43 |
--------------------------------------------------------------------------------
/src/chaintool/core.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.core
16 | (:require [chaintool.subcommands.build :as buildcmd]
17 | [chaintool.subcommands.buildcar :as buildcarcmd]
18 | [chaintool.subcommands.deps :as depscmd]
19 | [chaintool.subcommands.clean :as cleancmd]
20 | [chaintool.subcommands.inspect :as inspectcmd]
21 | [chaintool.subcommands.ls :as lscmd]
22 | [chaintool.subcommands.package :as packagecmd]
23 | [chaintool.subcommands.proto :as protocmd]
24 | [chaintool.subcommands.unpack :as unpackcmd]
25 | [chaintool.subcommands.env :as envcmd]
26 | [chaintool.util :as util]
27 | [clojure.string :as string]
28 | [clojure.tools.cli :refer [parse-opts]]
29 | [slingshot.slingshot :as slingshot])
30 | (:gen-class))
31 |
32 | (defn option-merge [& args] (vec (apply concat args)))
33 |
34 | ;; options common to all modes, top-level as well as subcommands
35 | (def common-options
36 | [["-h" "--help"]])
37 |
38 | (def toplevel-options
39 | (option-merge [["-v" "--version" "Print the version and exit"]]
40 | common-options))
41 |
42 | ;; these options are common to subcommands that are expected to operate on a chaincode tree
43 | (def common-path-options
44 | (option-merge [["-p" "--path PATH" "path to chaincode project" :default "./"]]
45 | common-options))
46 |
47 | (def subcommand-descriptors
48 | [{:name "build" :desc "Build the chaincode project"
49 | :handler buildcmd/run
50 | :options (option-merge [["-o" "--output NAME" "path to the output destination"]]
51 | common-path-options)}
52 |
53 | {:name "buildcar" :desc "Build the chaincode project from a CAR file"
54 | :handler buildcarcmd/run
55 | :arguments "path/to/file.car"
56 | :validate (fn [options arguments] (= (count arguments) 1))
57 | :options (option-merge [["-o" "--output NAME" "path to the output destination"]]
58 | common-options)}
59 |
60 | {:name "deps" :desc "Download any missing dependencies for the project"
61 | :handler depscmd/run
62 | :options common-path-options}
63 |
64 | {:name "clean" :desc "Clean the chaincode project"
65 | :handler cleancmd/run
66 | :options common-path-options}
67 |
68 | {:name "package" :desc "Package the chaincode into a CAR file for deployment"
69 | :handler packagecmd/run
70 | :options (option-merge [["-o" "--output NAME" "path to the output destination"]
71 | ["-c" "--compress NAME" "compression algorithm to use" :default "gzip"]]
72 | common-path-options)}
73 |
74 | {:name "unpack" :desc "Unpackage a CAR file"
75 | :handler unpackcmd/run
76 | :arguments "path/to/file.car"
77 | :validate (fn [options arguments] (= (count arguments) 1))
78 | :options (option-merge [["-d" "--directory NAME" "path to the output destination"]]
79 | common-options)}
80 |
81 | {:name "ls" :desc "List the contents of a CAR file"
82 | :handler lscmd/run
83 | :arguments "path/to/file.car"
84 | :validate (fn [options arguments] (= (count arguments) 1))
85 | :options common-options}
86 |
87 | {:name "env" :desc "Display variables used in the build environment"
88 | :handler envcmd/run
89 | :options common-path-options}
90 |
91 | {:name "proto" :desc "Compiles a CCI file to a .proto"
92 | :handler protocmd/run
93 | :arguments "path/to/file.cci"
94 | :validate (fn [options arguments] (>= (count arguments) 1))
95 | :options (option-merge [["-o" "--output NAME" "path to the output destination"]]
96 | common-options)}
97 |
98 | {:name "inspect" :desc "Retrieves metadata from a running instance"
99 | :handler inspectcmd/run
100 | :validate (fn [options arguments] (:name options))
101 | :options (option-merge [[nil "--host HOST" "The API hostname of the running fabric"
102 | :default "localhost"]
103 | [nil "--port PORT" "The API port of the running fabric"
104 | :default 5000
105 | :parse-fn #(Integer/parseInt %)
106 | :validate [#(< 0 % 65536) "Must be a number between 0 and 65536"]]
107 | ["-n" "--name NAME" "The name of the chaincode instance"]
108 | ["-i" "--interfaces PATH" "retrieve interfaces from endpoint and saves them to PATH"]]
109 | common-options)}])
110 |
111 | ;; N.B. the resulting map values are vectors each with a single map as an element
112 | ;;
113 | (def subcommands (group-by :name subcommand-descriptors))
114 |
115 | (defn exit [status msg & rest]
116 | (do
117 | (apply println msg rest)
118 | status))
119 |
120 | (defn version [] (str "chaintool version: v" util/app-version))
121 |
122 | (defn prep-usage [msg] (->> msg flatten (string/join \newline)))
123 |
124 | (defn usage [options-summary]
125 | (prep-usage [(version)
126 | ""
127 | "Usage: chaintool [general-options] action [action-options]"
128 | ""
129 | "General Options:"
130 | options-summary
131 | ""
132 | "Actions:"
133 | (map (fn [[_ [{:keys [name desc]}]]] (str " " name " -> " desc)) subcommands)
134 | ""
135 | "(run \"chaintool -h\" for action specific help)"]))
136 |
137 | (defn subcommand-usage [subcommand options-summary]
138 | (prep-usage [(version)
139 | ""
140 | (str "Description: chaintool " (:name subcommand) " - " (:desc subcommand))
141 | ""
142 | (str "Usage: chaintool " (:name subcommand) " [options] " (when-let [arguments (:arguments subcommand)] arguments))
143 | ""
144 | "Command Options:"
145 | options-summary
146 | ""]))
147 |
148 | (defn -app [& args]
149 | (let [{:keys [options arguments errors summary]} (parse-opts args toplevel-options :in-order true)]
150 | (cond
151 |
152 | (:help options)
153 | (exit 0 (usage summary))
154 |
155 | (not= errors nil)
156 | (exit -1 "Error: " (string/join errors))
157 |
158 | (:version options)
159 | (exit 0 (version))
160 |
161 | (zero? (count arguments))
162 | (exit -1 (usage summary))
163 |
164 | :else
165 | (if-let [[subcommand] (subcommands (first arguments))]
166 | (let [{:keys [options arguments errors summary]} (parse-opts (rest arguments) (:options subcommand))]
167 | (cond
168 |
169 | (:help options)
170 | (exit 0 (subcommand-usage subcommand summary))
171 |
172 | (not= errors nil)
173 | (exit -1 "Error: " (string/join errors))
174 |
175 | (and (:validate subcommand) (not ((:validate subcommand) options arguments)))
176 | (exit -1 (subcommand-usage subcommand summary))
177 |
178 | :else
179 | (slingshot/try+
180 | ((:handler subcommand) options arguments)
181 | (exit 0 "")
182 | (catch [:type :chaintoolabort] {:keys [msg retval]}
183 | (exit retval (str "Error: " msg))))))
184 |
185 | ;; unrecognized subcommand
186 | (exit 1 (usage summary))))))
187 |
188 | (defn -main [& args]
189 | (System/exit (apply -app args)))
190 |
--------------------------------------------------------------------------------
/src/chaintool/inspect/core.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.inspect.core
16 | (:import [org.hyperledger.chaintool.meta
17 | OrgHyperledgerChaintoolMeta$GetInterfacesParams
18 | OrgHyperledgerChaintoolMeta$Interfaces
19 | OrgHyperledgerChaintoolMeta$InterfaceDescriptor
20 | OrgHyperledgerChaintoolMeta$GetFactsParams
21 | OrgHyperledgerChaintoolMeta$Facts])
22 | (:require [clojure.java.io :as io]
23 | [clj-http.client :as http]
24 | [flatland.protobuf.core :as fl]
25 | [clojure.data.codec.base64 :as base64]
26 | [cheshire.core :as json]
27 | [chaintool.codecs :as codecs]
28 | [chaintool.util :as util]
29 | [doric.core :as doric]))
30 |
31 | (def GetInterfacesParams (fl/protodef OrgHyperledgerChaintoolMeta$GetInterfacesParams))
32 | (def Interfaces (fl/protodef OrgHyperledgerChaintoolMeta$Interfaces))
33 | (def InterfaceDescriptor (fl/protodef OrgHyperledgerChaintoolMeta$InterfaceDescriptor))
34 | (def GetFactsParams (fl/protodef OrgHyperledgerChaintoolMeta$GetFactsParams))
35 | (def Facts (fl/protodef OrgHyperledgerChaintoolMeta$Facts))
36 |
37 | (defn- encode [item] (-> item fl/protobuf-dump base64/encode (String. "UTF-8")))
38 | (defn- decode [type item] (->> item .getBytes base64/decode (fl/protobuf-load type)))
39 |
40 | (defn- url [{:keys [host port]}]
41 | (str "http://" host ":" port "/chaincode"))
42 |
43 | ;;--------------------------------------------------------------------------------------
44 | ;; post - performs a synchronous http/jsonrpc to the server, evaluating to the response
45 | ;;--------------------------------------------------------------------------------------
46 | (defn- post [{:keys [method name func args] :as options}]
47 | (let [body {:jsonrpc "2.0"
48 | :method method
49 | :params {:type 3
50 | :chaincodeID {:name name}
51 | :ctorMsg {:function func
52 | :args [(encode args)]}}
53 | :id "1"}]
54 |
55 | (http/post (url options)
56 | {:content-type :json
57 | :accept :json
58 | :form-params body})))
59 |
60 | ;;--------------------------------------------------------------------------------------
61 | ;; invokes a "query" operation on top of (post) and evaluates to a successful response
62 | ;; or throws an exception
63 | ;;--------------------------------------------------------------------------------------
64 | (defn- query [args]
65 | (let [{:keys [body]} (post (assoc args :method "query"))
66 | response (-> body (json/parse-string true) (select-keys [:result :error]))]
67 |
68 | (if (= (-> response :result :status) "OK")
69 | (->> response :result :message)
70 | ;; else
71 | (util/abort -1 (str response)))))
72 |
73 | ;;--------------------------------------------------------------------------------------
74 | ;; get-* operations invoke specific query operations
75 | ;;--------------------------------------------------------------------------------------
76 | (defn- get-interfaces
77 | "gets all interface names declared, optionally with a request to include cci content"
78 | [{:keys [host port] :as options}]
79 | (let [response (query (assoc options
80 | :func "org.hyperledger.chaintool.meta/query/1"
81 | :args (fl/protobuf GetInterfacesParams :IncludeContent (some? (:interfaces options)))))]
82 |
83 | (decode Interfaces response)))
84 |
85 | (defn- get-facts
86 | "gets all fact name/value pairs from the running instance"
87 | [{:keys [host port] :as options}]
88 | (let [response (query (assoc options
89 | :func "org.hyperledger.chaintool.meta/query/3"
90 | :args (fl/protobuf GetFactsParams)))]
91 |
92 | (decode Facts response)))
93 |
94 | ;;--------------------------------------------------------------------------------------
95 | (defn run
96 | "main entrypoint for inspection function"
97 | [options]
98 |
99 | (println "Connecting to" (url options))
100 |
101 | (let [{:keys [facts]} (get-facts options)
102 | interfaces (get-interfaces options)]
103 |
104 | (println (doric/table [{:name :name :title "Fact"} {:name :value}] facts))
105 |
106 | (println "Exported Interfaces:")
107 | (dorun (for [{:keys [name data]} (:descriptors interfaces)]
108 | (do
109 | (println "\t-" name)
110 | (when-let [path (:interfaces options)]
111 | (let [is (->> data .newInput (codecs/decompressor "gzip"))
112 | file (io/file path (str name ".cci"))]
113 |
114 | (io/make-parents file)
115 | (with-open [os (io/output-stream file)]
116 | (io/copy is os)))))))))
117 |
--------------------------------------------------------------------------------
/src/chaintool/platforms/api.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.platforms.api)
16 |
17 | (defprotocol Platform
18 | ;; Displays environment variables relevant to the build environment
19 | (env [this params])
20 | ;; Compiles the platform
21 | (build [this params])
22 | ;; Downloads any missing deps for the platform
23 | (deps [this params])
24 | ;; Cleans any previous builds of the platform
25 | (clean [this params])
26 | ;; Packages the chaincode project according to the platform
27 | (package [this params]))
28 |
--------------------------------------------------------------------------------
/src/chaintool/platforms/core.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.platforms.core
16 | (:require [chaintool.platforms.golang.system :as syscc]
17 | [chaintool.platforms.golang.userspace :as golang]
18 | [chaintool.util :as util])
19 | (:refer-clojure :exclude [find]))
20 |
21 | (def factories
22 | {"org.hyperledger.chaincode.golang" golang/factory
23 | "org.hyperledger.chaincode.system" syscc/factory})
24 |
25 | (defn find [config]
26 | (let [platform (:Platform config)
27 | name (:Name platform)
28 | version (:Version platform)]
29 | (if-let [factory (factories name)]
30 | (factory version)
31 | (util/abort -1 (str "Unknown platform type: \"" name "\"")))))
32 |
--------------------------------------------------------------------------------
/src/chaintool/platforms/golang/system.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.platforms.golang.system
16 | (:require [chaintool.platforms.api :as platforms.api]
17 | [chaintool.platforms.golang.core :refer :all]
18 | [chaintool.util :as util]
19 | [clojure.java.io :as io]
20 | [clojure.java.shell :refer [sh]]
21 | [clojure.string :as string]
22 | [clojure.tools.file-utils :as fileutils])
23 | (:refer-clojure :exclude [compile]))
24 |
25 | (defn get-package-name [path]
26 | (let [ {:keys [out err exit]} (sh "go" "list" :dir path)]
27 | (if (zero? exit)
28 | (string/trim-newline out)
29 | (util/abort -1 (str "\"go list\" returned: " err)))))
30 |
31 | (defn subtract-paths [fqpath relpath]
32 | (->> (string/replace (str fqpath) relpath "") io/file .getCanonicalPath str))
33 |
34 | (defn get-fqp [path]
35 | (->> path io/file .getCanonicalPath))
36 |
37 | (defn compute-gopath [path pkgname]
38 | (->> pkgname pkg-to-relpath (subtract-paths (get-fqp path))))
39 |
40 | ;;-----------------------------------------------------------------
41 | ;; Supports "org.hyperledger.chaincode.system" platform, a golang
42 | ;; based environment for system chaincode applications.
43 | ;;-----------------------------------------------------------------
44 | (deftype GolangSystemPlatform []
45 | platforms.api/Platform
46 |
47 | ;;-----------------------------------------------------------------
48 | ;; env - Emits the GOPATH used for building system chaincode
49 | ;;-----------------------------------------------------------------
50 | (env [_ _])
51 |
52 | ;;-----------------------------------------------------------------
53 | ;; build - generates all golang platform artifacts within the
54 | ;; default location in the build area
55 | ;;-----------------------------------------------------------------
56 | (build [_ {:keys [path config output]}]
57 | (let [builddir "vendor"
58 | opath (io/file path builddir)
59 | pkgname (get-package-name path)]
60 |
61 | ;; ensure we clean up any previous runs
62 | (fileutils/recursive-delete opath)
63 |
64 | ;; run our code generator
65 | (generate {:base "hyperledger"
66 | :package pkgname
67 | :ipath (io/file path "interfaces")
68 | :opath opath
69 | :config config})
70 |
71 | (println "Compilation complete")))
72 |
73 | ;;-----------------------------------------------------------------
74 | ;; deps - not supported for system chaincode
75 | ;;-----------------------------------------------------------------
76 | (deps [_ {:keys [path]}]
77 | (util/abort -1 "unsupported platform operation: deps"))
78 |
79 | ;;-----------------------------------------------------------------
80 | ;; clean - cleans up any artifacts from a previous build, if any
81 | ;;-----------------------------------------------------------------
82 | (clean [_ {:keys [path]}]
83 | (fileutils/recursive-delete (io/file path "vendor")))
84 |
85 | ;;-----------------------------------------------------------------
86 | ;; package - not supported for system chaincode
87 | ;;-----------------------------------------------------------------
88 | (package [_ _]
89 | (util/abort -1 "unsupported platform operation: package")))
90 |
91 | (defn factory [version]
92 | (if (= version 1)
93 | (GolangSystemPlatform.)
94 | (util/abort -1 (str "Version " version " not supported"))))
95 |
--------------------------------------------------------------------------------
/src/chaintool/protobuf/generate.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.protobuf.generate
16 | (:require [chaintool.build.interface :as intf]
17 | [chaintool.util :as util]
18 | [clojure.zip :as zip])
19 | (:import (java.util ArrayList)
20 | (org.stringtemplate.v4 STGroupFile))
21 | (:refer-clojure :exclude [compile]))
22 |
23 | ;; types to map to java objects that string template expects.
24 | ;;
25 |
26 | (deftype Field [^String modifier ^String type ^String name ^String index])
27 | (deftype Definition [^String type ^String name ^ArrayList entries])
28 | (deftype Entry [^Definition message ^Definition enum ^Field field ^Definition oneof])
29 | (deftype Function [^String key ^String rettype ^String name ^String param])
30 |
31 | (defn- typeconvert [[prefix name :as inType]]
32 | (cond
33 |
34 | (= prefix :map) (let [[_ keyType valueType] inType]
35 | (str "map" "<" (second keyType) "," (-> valueType second second) ">"))
36 | :else name))
37 |
38 | (defn- find-toplevel-definitions [ast]
39 | (loop [loc (->> ast zip/down zip/right) defs []]
40 | (cond
41 |
42 | (nil? loc)
43 | defs
44 |
45 | :else
46 | (let [type (->> loc zip/down zip/node)]
47 | (recur (zip/right loc)
48 | (if (or (= type :message) (= type :enum))
49 | (conj defs loc)
50 | defs))))))
51 |
52 | (defn- getallfunctions [ast]
53 | (let [{:keys [functions]} (intf/getallfunctions ast)]
54 | (-> functions
55 | vals
56 | flatten)))
57 |
58 | ;;-----------------------------------------------------------------
59 | ;; buildX - build our ST friendly objects from the AST
60 | ;;-----------------------------------------------------------------
61 | (defn- build-msgfield [ast]
62 | (let [field (zip/down ast)
63 | {:keys [modifier type fieldName index]} (intf/getattrs field)]
64 | (->Entry nil nil (->Field modifier (typeconvert type) fieldName index) nil)))
65 |
66 | (defn- build-oneoffield [ast]
67 | (let [field (zip/down ast)
68 | {:keys [modifier type fieldName index]} (intf/getattrs field)]
69 | (->Field modifier (typeconvert type) fieldName index)))
70 |
71 | (defn- build-enumfield [ast]
72 | (let [field (zip/down ast)
73 | name (->> field zip/right zip/node)
74 | index (->> field zip/right zip/right zip/node)]
75 | (->Field nil nil name index)))
76 |
77 | (declare build-message)
78 | (declare build-enum)
79 | (declare build-oneof)
80 | (defn- build-subentry [ast]
81 | (let [type (->> ast zip/down zip/node)]
82 | (case type
83 | :message (build-message ast)
84 | :enum (build-enum ast)
85 | :field (build-msgfield ast)
86 | :oneof (build-oneof ast))))
87 |
88 | (defn- build-message [ast]
89 | (let [elem (zip/down ast)
90 | name (->> elem zip/right zip/node)
91 | first (->> elem zip/right zip/right)
92 | entries (loop [loc first entries {} index 0]
93 | (cond
94 |
95 | (nil? loc)
96 | entries
97 |
98 | :else
99 | (recur (zip/right loc) (assoc entries index (build-subentry loc)) (inc index))))]
100 | (->Entry (->Definition "message" name entries) nil nil nil)))
101 |
102 | (defn- build-enum [ast]
103 | (let [elem (zip/down ast)
104 | name (->> elem zip/right zip/node)
105 | first (->> elem zip/right zip/right)
106 | entries (loop [loc first entries {} index 0]
107 | (cond
108 |
109 | (nil? loc)
110 | entries
111 |
112 | :else
113 | (recur (zip/right loc) (assoc entries index (build-enumfield loc)) (inc index))))]
114 | (->Entry nil (->Definition "enum" name entries) nil nil)))
115 |
116 | (defn- build-oneof [ast]
117 | (let [elem (zip/down ast)
118 | name (->> elem zip/right zip/node)
119 | first (->> elem zip/right zip/right)
120 | entries (loop [loc first entries {} index 0]
121 | (cond
122 |
123 | (nil? loc)
124 | entries
125 |
126 | :else
127 | (recur (zip/right loc) (assoc entries index (build-oneoffield loc)) (inc index))))]
128 | (->Entry nil nil nil (->Definition "oneof" name entries))))
129 |
130 | (defn- build-toplevel-entry [ast]
131 | (let [type (->> ast zip/down zip/node)]
132 | (case type
133 | :message (build-message ast)
134 | :enum (build-enum ast))))
135 |
136 | (defn- build-toplevel-entries [ast]
137 | (->> ast
138 | find-toplevel-definitions
139 | (mapv build-toplevel-entry)
140 | (interleave (range))
141 | (partition 2)
142 | (mapv vec)
143 | (into {})))
144 |
145 | (defn- buildfunction [name {:keys [rettype functionName param index] :as ast}]
146 | (let [key (str name "/fcn/" index)]
147 | (->Function key rettype functionName param)))
148 |
149 | (defn- buildfunctions [name ast]
150 | (let [funcs (map #(buildfunction name %) (getallfunctions ast))]
151 | (into {} (map #(vector (.key %) %) funcs))))
152 |
153 | ;;-----------------------------------------------------------------
154 | ;; to-string - compiles the interface into a protobuf
155 | ;; specification in a string, suitable for writing to a file or
156 | ;; passing to protoc
157 | ;;-----------------------------------------------------------------
158 | (defn to-string [package [name ast]]
159 | (let [definitions (build-toplevel-entries ast)
160 | functions (buildfunctions name ast)
161 | stg (STGroupFile. "generators/proto.stg")
162 | template (.getInstanceOf stg "protobuf")]
163 |
164 | (.add template "package" (if (nil? package) name package))
165 | (.add template "definitions" definitions)
166 | (.add template "functions" functions)
167 | (.render template)))
168 |
169 | ;;-----------------------------------------------------------------
170 | ;; to-file - generates a protobuf specification and writes
171 | ;; it to a file
172 | ;;-----------------------------------------------------------------
173 | (defn to-file [filename package interface]
174 | (util/truncate-file filename (to-string package interface)))
175 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/build.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.build
15 | (:require [clojure.java.io :as io]
16 | [chaintool.config.util :as config.util]
17 | [chaintool.build.core :as build.core]))
18 |
19 | (defn getoutput [options path config]
20 | (if-let [output (:output options)]
21 | (io/file output)
22 | (io/file path "build/bin" (config.util/compositename config))))
23 |
24 | (defn run [options args]
25 | (let [[path config] (config.util/load-from-options options)
26 | output (getoutput options path config)]
27 | (println "Build using configuration for " path)
28 | (build.core/compile {:path path :config config :output output})))
29 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/buildcar.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.buildcar
15 | (:require [clojure.java.io :as io]
16 | [me.raynes.fs :as fs]
17 | [clojure.tools.file-utils :as fileutils]
18 | [chaintool.util :as util]
19 | [chaintool.config.util :as config.util]
20 | [chaintool.car.read :as car.read]
21 | [chaintool.car.unpack :as car.unpack]
22 | [chaintool.build.core :as build.core]))
23 |
24 | (defn getoutput [options]
25 | (if-let [output (:output options)]
26 | (io/file output)
27 | (util/abort -1 "Missing -o output (see -h for details)")))
28 |
29 | (defn run [options args]
30 | (let [output (getoutput options)
31 | file (io/file (first args))
32 | {:keys [index config]} (with-open [is (io/input-stream file)] (car.read/read is))
33 | workingdir (fs/temp-dir "buildcar-")]
34 |
35 | (car.unpack/unpack index workingdir :false)
36 | (let [config (config.util/load workingdir)]
37 | (println "Building CAR" (.getCanonicalPath file))
38 | (build.core/compile {:path workingdir :config config :output output})
39 | (fileutils/recursive-delete (io/file workingdir)))))
40 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/clean.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.clean
15 | (:require [chaintool.config.util :as config.util]
16 | [chaintool.platforms.core :as platforms.core]
17 | [chaintool.platforms.api :as platforms.api]))
18 |
19 | (defn run [options args]
20 | (let [[path config] (config.util/load-from-options options)]
21 | (when-let [platform (platforms.core/find config)]
22 | (println "Cleaning project found at " path)
23 | (platforms.api/clean platform {:path path}))))
24 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/deps.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright Greg Haskins, 2017 All Rights Reserved.
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 | (ns chaintool.subcommands.deps
15 | (:require [chaintool.config.util :as config.util]
16 | [chaintool.platforms.core :as platforms.core]
17 | [chaintool.platforms.api :as platforms.api]))
18 |
19 | (defn run [options args]
20 | (let [[path config] (config.util/load-from-options options)]
21 | (when-let [platform (platforms.core/find config)]
22 | (platforms.api/deps platform {:path path :config config}))))
23 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/env.clj:
--------------------------------------------------------------------------------
1 | ;; Licensed under the Apache License, Version 2.0 (the "License");
2 | ;; you may not use this file except in compliance with the License.
3 | ;; You may obtain a copy of the License at
4 | ;;
5 | ;; http://www.apache.org/licenses/LICENSE-2.0
6 | ;;
7 | ;; Unless required by applicable law or agreed to in writing, software
8 | ;; distributed under the License is distributed on an "AS IS" BASIS,
9 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | ;; See the License for the specific language governing permissions and
11 | ;; limitations under the License.
12 |
13 | (ns chaintool.subcommands.env
14 | (:require [chaintool.config.util :as config.util]
15 | [chaintool.build.core :as build.core]))
16 |
17 | (defn run [options args]
18 | (let [[path config] (config.util/load-from-options options)]
19 | (build.core/env {:path path :config config})))
20 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/inspect.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.inspect
16 | (:require [chaintool.inspect.core :as inspect]
17 | [clojure.java.io :as io]))
18 |
19 | (defn getoutputdir [options]
20 | (if-let [path (:interfaces options)]
21 | (io/file path)
22 | (io/file ".")))
23 |
24 | (defn run [options args]
25 | (let [output (getoutputdir options)]
26 | (inspect/run (assoc options :output output))))
27 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/ls.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.ls
16 | (:require [chaintool.car.ls :as car]
17 | [clojure.java.io :as io]))
18 |
19 | (defn run [options args]
20 | (let [file (io/file (first args))]
21 | (car/ls file)))
22 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/package.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.package
15 | (:require [chaintool.config.util :as config]
16 | [chaintool.platforms.core :as platforms.core]
17 | [chaintool.platforms.api :as platforms.api]
18 | [clojure.java.io :as io]
19 | [clojure.tools.cli :refer [parse-opts]]))
20 |
21 | (defn getoutputfile [options path config]
22 | (if-let [output (:output options)]
23 | (io/file output)
24 | (io/file path "build" (str (config/compositename config) ".car"))))
25 |
26 | (defn run [options args]
27 | (let [[path config] (config/load-from-options options)
28 | compressiontype (:compress options)
29 | outputfile (getoutputfile options path config)
30 | platform (platforms.core/find config)]
31 |
32 | (platforms.api/package platform {:path path
33 | :config config
34 | :compressiontype compressiontype
35 | :outputfile outputfile})))
36 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/proto.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.proto
16 | (:require [chaintool.build.interface :as intf]
17 | [chaintool.protobuf.generate :as pb]
18 | [chaintool.util :as util]
19 | [clojure.java.io :as io]
20 | [me.raynes.fs :as fs]
21 | [clojure.string :as str]))
22 |
23 | (defn getoutputfile [options input name]
24 | (if-let [output (:output options)]
25 | (io/file (str output (when-not (str/ends-with? output "/") "/") name ".proto"))
26 | (io/file (str name ".proto"))))
27 |
28 | (defn run [options args]
29 | (doseq [raw_input args]
30 | (let [input (io/file raw_input)
31 | name (fs/base-name input true)
32 | output (getoutputfile options input name)
33 | intf (intf/compileintf {:path (.getCanonicalPath input) :data (util/safe-slurp input)})]
34 | (pb/to-file output name [name intf]))))
35 |
--------------------------------------------------------------------------------
/src/chaintool/subcommands/unpack.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.subcommands.unpack
16 | (:require [chaintool.config.util :as config]
17 | [chaintool.util :as util]
18 | [chaintool.car.read :as car.read]
19 | [chaintool.car.unpack :as car.unpack]
20 | [clojure.java.io :as io]))
21 |
22 | (defn getoutputdir [options config]
23 | (if-let [dir (:directory options)]
24 | (io/file dir)
25 | (io/file "./" (str (config/compositename config)))))
26 |
27 | (defn run [options args]
28 | (let [file (io/file (first args))
29 | {:keys [index config]} (with-open [is (io/input-stream file)] (car.read/read is))
30 | outputdir (getoutputdir options config)]
31 |
32 | (when (.exists outputdir)
33 | (util/abort -1 (str "output directory " (.getCanonicalPath outputdir) " exists")))
34 |
35 | (println "Unpacking CAR to:" (.getCanonicalPath outputdir))
36 | (println)
37 | (car.unpack/unpack index outputdir :true)))
38 |
--------------------------------------------------------------------------------
/src/chaintool/util.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.util
16 | (:require [clojure.java.io :as io]
17 | [slingshot.slingshot :as slingshot]))
18 |
19 | (def app-version (System/getProperty "chaintool.version"))
20 |
21 | (defn truncate-file [filename content]
22 |
23 | ;; ensure the path exists
24 | (io/make-parents filename)
25 |
26 | ;; and blast it out to the filesystem
27 | (spit filename content :truncate true))
28 |
29 | ;; throws an exception that should unwind us all the way to the core/main
30 | ;; function and exit cleanly with an error message rather than a stacktrace, etc
31 | (defn abort [retval msg]
32 | (slingshot/throw+ {:type :chaintoolabort :retval retval :msg msg}))
33 |
34 | (defn safe-slurp [file]
35 | (if (.exists file)
36 | (slurp file)
37 | (abort -1 (str (.getCanonicalPath file) " not found"))))
38 |
--------------------------------------------------------------------------------
/test/chaintool/build/test_interface.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.build.test_interface
16 | (:require [clojure.test :refer :all]
17 | [chaintool.build.interface :refer :all]
18 | [chaintool.ast :as ast]
19 | [slingshot.slingshot :as slingshot]
20 | [clojure.pprint :refer [pprint]]
21 | [clojure.zip :as zip])
22 | (:refer-clojure :exclude [compile]))
23 |
24 | (def example1-cci
25 | "
26 | # This is a comment
27 | // So is this
28 |
29 | message ActiveMessage {
30 | // mid-message comment
31 | string param1 = 1; # trailing comment
32 | int32 param2 = 2;
33 | int64 param3 = 3;
34 | }
35 |
36 | //message CommentedMessage {
37 | // int32 param1 = 1;
38 | //}
39 | ")
40 |
41 | (def example1-expected-result
42 | [[:interface [:message "ActiveMessage" [:field [:type [:scalar "string"]] [:fieldName "param1"] [:index "1"]] [:field [:type [:scalar "int32"]] [:fieldName "param2"] [:index "2"]] [:field [:type [:scalar "int64"]] [:fieldName "param3"] [:index "3"]]]] nil])
43 |
44 | (def example2-cci
45 | "
46 | message NestedMessage {
47 | message Entry {
48 | string key = 1;
49 | int32 value = 2;
50 | }
51 |
52 | repeated Entry entries = 1;
53 | }
54 |
55 | ")
56 |
57 | (def example2-expected-result
58 | [[:interface [:message "NestedMessage" [:message "Entry" [:field [:type [:scalar "string"]] [:fieldName "key"] [:index "1"]] [:field [:type [:scalar "int32"]] [:fieldName "value"] [:index "2"]]] [:field [:modifier "repeated"] [:type [:userType "Entry"]] [:fieldName "entries"] [:index "1"]]]] nil])
59 |
60 | (deftest test-parser-output
61 | (is (= example1-expected-result (parse example1-cci)))
62 | (is (= example2-expected-result (parse example2-cci))))
63 |
64 | (def map-example-cci
65 | "
66 | message MapMessage {
67 | map testmap = 1;
68 | }
69 | "
70 | )
71 |
72 | (def map-example-expected-result
73 | [[:interface [:message "MapMessage" [:field [:type [:map [:keyType "string"] [:type [:scalar "string"]]]] [:fieldName "testmap"] [:index "1"]]]] nil])
74 |
75 |
76 | (deftest test-map-parser-output
77 | (is (= map-example-expected-result (parse map-example-cci))))
78 |
79 | (def oneof-example-cci
80 | "
81 | message OneofTest {
82 |
83 | oneof Test {
84 | string account = 4;
85 | double loan = 5;
86 | }
87 |
88 | }
89 | "
90 | )
91 |
92 | (def oneof-example-expected-result
93 | [[ :interface [ :message "OneofTest" [ :oneof "Test" [ :field [ :type [ :scalar "string" ] ] [ :fieldName "account" ] [ :index "4" ] ] [ :field [ :type [ :scalar "double" ] ] [ :fieldName "loan" ] [ :index "5" ] ] ] ] ] nil])
94 |
95 | (deftest test-oneof-parser-output
96 | (is (= oneof-example-expected-result (parse oneof-example-cci))))
97 |
98 | (def example-undefined-type-cci
99 | "
100 | message BadMessage {
101 | message Entry {
102 | string key = 1;
103 | UnknownType value = 2;
104 | }
105 |
106 | repeated Entry entries = 1;
107 | }
108 |
109 | ")
110 |
111 | (deftest test-parser-validation
112 | (let [intf (parse example-undefined-type-cci)]
113 | (is (some? (verify-intf intf)))))
114 |
115 | (def example-type-resolution
116 | "
117 | message Party {
118 | string entity = 1;
119 | int32 value = 2;
120 | }
121 |
122 | message Init {
123 | Party partyA = 1;
124 | Party partyB = 2;
125 | }
126 | ")
127 |
128 | (deftest test-type-resolution
129 | (let [intf (parse example-type-resolution)]
130 | (is (nil? (verify-intf intf)))))
131 |
132 | (def example-conflicting-index
133 | "
134 | message Conflict {
135 | string foo = 1;
136 | int32 bar = 2;
137 | int32 baz = 1;
138 | }
139 |
140 | ")
141 |
142 | (deftest test-conflict-detection
143 | (let [intf (parse example-conflicting-index)]
144 | (is (some? (verify-intf intf)))))
145 |
146 | (def example-enum
147 | "
148 | enum MyEnum {
149 | ZERO = 0;
150 | ONE = 1;
151 | TWO = 2;
152 | }
153 |
154 | ")
155 |
156 | (deftest test-enum
157 | (let [intf (parse example-enum)]
158 | (is (nil? (verify-intf intf)))))
159 |
160 | (def example-conflicting-enum
161 | "
162 | enum ConflictingEnum {
163 | ZERO = 0;
164 | ONE = 1;
165 | TWO = 1;
166 | }
167 |
168 | ")
169 |
170 | (deftest test-conflicting-enum
171 | (let [intf (parse example-conflicting-enum)]
172 | (is (some? (verify-intf intf)))))
173 |
174 | (def example-bad-default-enum
175 | "
176 | enum BadDefaultEnum {
177 | ZERO = 1;
178 | ONE = 2;
179 | TWO = 3;
180 | }
181 |
182 | ")
183 |
184 | (deftest test-bad-default-enum
185 | (let [intf (parse example-bad-default-enum)]
186 | (is (some? (verify-intf intf)))))
187 |
188 | (def example-no-parameters
189 | "
190 | functions {
191 | string Parameterless() = 1;
192 | }
193 |
194 | ")
195 |
196 | (deftest test-no-parameters
197 | (let [intf (parse example-no-parameters)]
198 | (is (nil? (verify-intf intf)))))
199 |
200 | (def example-comment-before-msg
201 | "
202 | message Foo {}
203 | message Bar {
204 | // This comment should be fine
205 | string baz = 1;
206 | // This comment should not break the parser
207 | Foo my_foo = 2;
208 | }
209 | ")
210 |
211 | (deftest test-comment-before-msg
212 | (let [intf (parse example-comment-before-msg)]
213 | (is (nil? (verify-intf intf)))))
214 |
215 | (def fabct-53-msg ;; https://jira.hyperledger.org/browse/FABCT-53
216 | "message Foo {
217 | enum MyEnum { a = 0;}
218 | }
219 |
220 | message Bar {
221 | Foo.MyEnum my_field = 1;
222 | }
223 | ")
224 |
225 | (defn find-usertype [x]
226 | (->> (ast/find :userType x) zip/node second))
227 |
228 | (deftest test-fabct-53
229 | (testing "Ensure we can cross-reference nested definitions"
230 | (let [intf (parse fabct-53-msg)]
231 | (is (nil? (verify-intf intf)))
232 | (is (= (find-usertype intf) "Foo.MyEnum")))))
233 |
--------------------------------------------------------------------------------
/test/chaintool/platforms/golang/test_core.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.platforms.golang.test_core
16 | (:require [clojure.test :refer :all]
17 | [chaintool.platforms.golang.core :refer :all])
18 | (:refer-clojure :exclude [compile]))
19 |
20 | (deftest test-buildgopath
21 | (let [gopath (buildgopath "foo")]
22 | (is (some? gopath))))
23 |
--------------------------------------------------------------------------------
/test/chaintool/platforms/golang/test_system.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.platforms.golang.test_system
16 | (:require [clojure.test :refer :all]
17 | [chaintool.platforms.golang.system :refer :all])
18 | (:refer-clojure :exclude [compile]))
19 |
20 | (deftest test-standalone-gopath-computation
21 | (let [gopath (compute-gopath "/local-dev/git/chaintool/testdata/sample_syscc"
22 | "_/local-dev/git/chaintool/testdata/sample_syscc")]
23 | (is (= gopath "/"))))
24 |
25 | (deftest test-gopath-computation
26 | (let [gopath (compute-gopath "/opt/gopath/src/github.com/hyperledger/fabric/core/system_chaincode/sample"
27 | "github.com/hyperledger/fabric/core/system_chaincode/sample")]
28 | (is (= gopath "/opt/gopath/src"))))
29 |
--------------------------------------------------------------------------------
/test/chaintool/protobuf/test_generate.clj:
--------------------------------------------------------------------------------
1 | ;; Copyright London Stock Exchange Group 2016 All Rights Reserved.
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 | (ns chaintool.protobuf.test_generate
16 | (:require [clojure.test :refer :all]
17 | [clojure.java.io :as io]
18 | [clojure.zip :as zip]
19 | [instaparse.core :as insta]
20 | [chaintool.ast :as ast]
21 | [chaintool.protobuf.generate :as pb]
22 | [slingshot.slingshot :as slingshot])
23 | (:refer-clojure :exclude [compile]))
24 |
25 | (def skipper (insta/parser (io/resource "parsers/proto/skip.bnf")))
26 | (def grammar (insta/parser (io/resource "parsers/proto/grammar.bnf") :auto-whitespace skipper))
27 |
28 | (defn- parse [intf]
29 | (let [result (insta/add-line-and-column-info-to-metadata intf (grammar intf))]
30 | (if (insta/failure? result)
31 | (let [{:keys [line column text]} result]
32 | (str "could not parse \"" text "\": line=" line " column=" column))
33 | (zip/vector-zip result))))
34 |
35 | (defn- find
36 | "Finds an arbitrary item in the tree based on (pred)"
37 | [ast pred]
38 | (loop [loc ast]
39 | (cond
40 |
41 | (or (nil? loc) (zip/end? loc))
42 | nil
43 |
44 | (pred loc)
45 | loc
46 |
47 | :else
48 | (recur (zip/next loc)))))
49 |
50 | (defn- tree-depth
51 | "Counts the zipper depth of the node represented by ast"
52 | [ast]
53 | (loop [loc ast depth 0]
54 | (cond
55 |
56 | (or (nil? loc) (zip/end? loc))
57 | depth
58 |
59 | :else
60 | (recur (zip/up loc) (inc depth)))))
61 |
62 | (defn- round-about
63 | "takes an AST, exports it to protobuf, and then reparses the protobuf back to a new AST"
64 | [ast]
65 | (let [pb (->> ["fictional.interface" ast] (pb/to-string "fictional.package"))]
66 | (parse pb)))
67 |
68 | (def nested-input
69 | (zip/vector-zip
70 | [:interface
71 | [:message "NestedMessage"
72 | [:message "Entry"
73 | [:field [:type [:scalar "string"]] [:fieldName "key"] [:index "1"]]
74 | [:field [:type [:scalar "int32"]] [:fieldName "value"] [:index "2"]]]
75 | [:field [:modifier "repeated"] [:type [:userType "Entry"]] [:fieldName "entries"] [:index "1"]]
76 | [:message "Level1"
77 | [:message "Level2"
78 | [:message "Level3"
79 | [:message "Level4"]]]]]]))
80 |
81 | (deftest nested-messages
82 | (let [result (round-about nested-input)
83 | level4 (find result (fn [loc] (= (zip/node loc) "Level4")))]
84 | (is level4)
85 | (is (= (tree-depth level4) 7))))
86 |
87 | (def enum-input
88 | (zip/vector-zip
89 | [:interface [:enum "MyEnum" [:enumField "ZERO" 0] [:enumField "ONE" 1] [:enumField "TWO" 2]]]))
90 |
91 | (deftest enum-test
92 | (let [result (round-about enum-input)]
93 | (is (= (->> result zip/down zip/node) :proto))
94 | (is (= (->> result (ast/find :syntax) zip/down zip/right zip/node) "proto3"))
95 | (is (= (->> result (ast/find :enum) zip/down zip/right zip/right zip/node) [:enumField "ZERO" "0"]))))
96 |
97 | (def map-input
98 | (zip/vector-zip
99 | [:interface
100 | [:message "MapMessage"
101 | [:field
102 | [:type
103 | [:map
104 | [:keyType "string"]
105 | [:type [:scalar "string"]]]]
106 | [:fieldName "testmap"] [:index "1"]]]]))
107 |
108 | (deftest map-test
109 | (let [result (round-about map-input)]
110 | (is (= (->> result zip/down zip/node) :proto ))
111 | (is (= (->> result (ast/find :syntax) zip/down zip/right zip/node) "proto3")
112 | (is (= (->> result (ast/find :map) zip/down zip/right zip/node) [:keyType "string"])))))
113 |
114 | (def parameterless-function
115 | (zip/vector-zip
116 | [:interface [:functions [:function [:rettype "string"] [:functionName "Parameterless"] [:index "1"]]]]))
117 |
118 | (deftest parameterless-test
119 | (let [result (round-about parameterless-function)]
120 | (some? result)))
121 |
--------------------------------------------------------------------------------