 ;; (make-tgz-package :golang "github.com/example_cc" "/home/jc/Work/clojure-fabric/resources/gocc")
 
 
+(defonce max-tx-file-size 1024)
+(defn tx-file->config-update
+  [tx-filename]
+  (let [tx-file (io/as-file tx-filename)]
+    (assert (<= (.length tx-file) max-tx-file-size))
+    (let [envelope (->> (with-open [in (io/input-stream tx-file)
+                                    out (java.io.ByteArrayOutputStream.)]
+                          (io/copy in out)
+                          (Common$Envelope/parseFrom (.toByteArray out))))]
+      (-> (proto/proto->clj envelope
+                            (proto/parse-trees :block-config-update-envelope))
+          (get-in [:payload :data :config-update])
+          ^Configtx$ConfigUpdate (proto/clj->proto)
+          (.toByteArray)))))
+;;;
+;;; Public API
+;;;
+
+(defn create-or-update-channel
+  ([orderer envelope]
+   (proto/broadcast-or-deliver-via-orderer :broadcast orderer envelope))
+  ([user channel-id orderer config-update signatures]
+   (->> (proto/make-config-update-envelope :config-update config-update :signatures signatures)
+        (chaincode/make-envelope channel-id user :config-update)
+        (create-or-update-channel orderer))))
+
+;; This is like create-channel
+(defn create-or-update-channel-from-nodes
+  [user channel-id orderer nodes config-update]
+  ;; participants = orderers + peers
+  (create-or-update-channel user
+                            channel-id
+                            orderer
+                            config-update
+                            (mapv (fn [node]
+                                    (make-config-signature node config-update {}))
+                                  nodes)))
+
+;; This is like create-user
+(defn new-user!
+  [{:keys [msp-id name]
+    :as args}]
+  ;; roles - client, auditor
+  ;; %roles - peer, validator
+  (swap! core/users assoc [msp-id name] (core/make-user args)))
+
+;;; get_chain
+(defn get-channel
+  "Get a chain instance from the state storage. This allows existing chain instances to be saved
+  for retrieval later and to be shared among instances of the application. Note that it's the 
+  application/SDK’s responsibility to record the chain information. If an application is not able to
+  look up the chain information from storage, it may call another API that queries one or more Peers
+  for that information.
+  Params:
+        name (str): The name of the chain
+  Returns:
+        (Chain instance or None): the chain instance for the name.
+  Error:  The state store has not been set
+        A chain does not exist under that name"
+  ;; Implementation Note:
+  ;;    Not a storage operation 
+  ([channel-name]
+   (get-channel core/*user* channel-name))
+  ([{:keys [channels]} channel-name]
+   (if-let [found (get channels channel-name)]
+     found
+     ;; Implementation Note
+     ;;       The spec says that Returns is chain Instance or None
+     ;;       How it can be None and also throw an exception?
+     (throw (Exception. "A channel does not exist under that name")))))
+
+;;; get_crypto_suite 
+(defn get-crypto-suite
+  "A convenience method for obtaining the CryptoSuite object in use for this client.
+  Params:
+        None
+  Returns:
+        (CryptoSuite instance): The CryptoSuite implementation object set within this Client, 
+        or null if it does not exist"
+  ([]
+   (get-crypto-suite core/*user*))
+  ([user]
+   (:crypto-suite user)))
+
 (defn install-chaincode
   ([name path version package-filename type target-peers]
    (install-chaincode core/*user* name path version package-filename target-peers))

          (known-channel-node? c node plural-type-key) true
          :else (recur more-c))))

(defn query-installed-chaincodes
  ([peer]
   (query-installed-chaincodes core/*user* peer))
  ([user peer]
   (if (known-user-node? user peer :peers)
     (first (chaincode/send-chaincode-request :query-installed-chaincodes
                                              system-channel-name
                                              peer
                                              user
                                              {}))
     (throw (Exception. "The target Peer does not know anything about the channel")))))

;;; get_name
(defn get-name
  "Get member name. Required property for the instance objects.

            [clojure-fabric.core :as core]
            [clojure-fabric.crypto-suite :as crypto-suite]
            [clojure-fabric.proto :as proto]
            [clojure.java.io :as io]
            [clojure-fabric.event-hub :as event-hub])
  (:import com.google.protobuf.ByteString
           [java.io ByteArrayOutputStream File FileInputStream]
           [org.apache.commons.compress.archivers.tar TarArchiveEntry TarArchiveOutputStream]
