diff --git a/go.mod b/go.mod index 94751e86b..09720382b 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,8 @@ replace google.golang.org/grpc => google.golang.org/grpc v1.29.1 require ( github.com/client9/misspell v0.3.4 github.com/golang/protobuf v1.5.3 - github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2 + github.com/hyperledger-labs/cc-tools v1.0.2 + github.com/hyperledger/fabric v2.1.1+incompatible github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a github.com/hyperledger/fabric-contract-api-go v1.2.1 github.com/hyperledger/fabric-protos-go v0.3.0 @@ -46,21 +47,12 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/BurntSushi/toml v1.2.1 // indirect - github.com/IBM/idemix v0.0.2-0.20231107110441-534ea4193b8f // indirect - github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231107110234-4cf31dd43660 // indirect - github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20231107110234-4cf31dd43660 // indirect - github.com/IBM/idemix/bccsp/types v0.0.0-20231107110234-4cf31dd43660 // indirect - github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da // indirect github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20231023164747-f3f972769504 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/cfssl v1.4.1 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/containerd/containerd v1.7.13 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -85,6 +77,7 @@ require ( github.com/google/certificate-transparency-go v1.0.21 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect + github.com/google/uuid v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 // indirect @@ -93,14 +86,12 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/joho/godotenv v1.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -145,5 +136,4 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect - rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index b59806168..11e9b9e2e 100644 --- a/go.sum +++ b/go.sum @@ -9,16 +9,6 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= -github.com/IBM/idemix v0.0.2-0.20231107110441-534ea4193b8f h1:SFWg5b/I49LcVurx/v7MFwQ4t/0wTX6TlPzxhEYEr3U= -github.com/IBM/idemix v0.0.2-0.20231107110441-534ea4193b8f/go.mod h1:nOEyL+adzVsbzAKiDV3/Qcn703tN6cdgGmVyXIfEhWg= -github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231107110234-4cf31dd43660 h1:Np3oYfF4a6SNtiPJCP8AQ5QDpajkT8UfWTkdlh3DfPQ= -github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231107110234-4cf31dd43660/go.mod h1:hO4IoGeT6yuwCduXpnvV4fskpjJi28ipZChV861S96E= -github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20231107110234-4cf31dd43660 h1:rdnFfRbHThWOzGcS7vR/iH67Pa9DeevsuOCHoE7dOi4= -github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20231107110234-4cf31dd43660/go.mod h1:FC0vVgNI6bv8GH0VTwjup+arwJ8Tau1iEhroWZ1oPwU= -github.com/IBM/idemix/bccsp/types v0.0.0-20231107110234-4cf31dd43660 h1:WFXPDH/S08C+/2gsV9982+Sc2FZX8ZLEpXbOS4u/pfY= -github.com/IBM/idemix/bccsp/types v0.0.0-20231107110234-4cf31dd43660/go.mod h1:IMIJ8WcUpBmV4gcOO/BYKuFYpdXCPYZjpNhFSUlO9b8= -github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da h1:qqGozq4tF6EOVnWoTgBoJGudRKKZXSAYnEtDggzTnsw= -github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da/go.mod h1:Tco9QzE3fQzjMS7nPbHDeFfydAzctStf1Pa8hsh6Hjs= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -26,16 +16,13 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/SmartBFT-Go/consensus v0.0.0-20230212211744-e5a79afcea81 h1:yiyJRAf/rsEu3Sl0ATWu1zREfyaj01i9VsPbGiXzZZw= -github.com/SmartBFT-Go/consensus v0.0.0-20230212211744-e5a79afcea81/go.mod h1:ZOD/ZiAdH9HpqdsJLlUTlbzYBr/qYEzyYx7wClbrH+w= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= -github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20231023164747-f3f972769504 h1:sQyFeDcHVHWJ3IeE437NSJjv0+J/6MvGQOJew4X+Cuw= -github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20231023164747-f3f972769504/go.mod h1:z5xq4Ji1RQojJLZzKeZH5+LKCVZxgQRZpQ4xAJWi8r0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -58,10 +45,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= -github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -80,10 +63,6 @@ github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6S github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= -github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= -github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is= github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -112,8 +91,11 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6 github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -194,6 +176,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -210,8 +193,9 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -234,6 +218,7 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -246,8 +231,10 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2 h1:w5BGxCYEsc9vjdDEdZGrZ5redvs263RYsdT2tqF7cNk= -github.com/hyperledger/fabric v1.4.0-rc1.0.20230405174026-695dd57e01c2/go.mod h1:LSwfuRgX/5C2uHkdT3hJtBFu/ALxuL7dFj1pmBby2R4= +github.com/hyperledger-labs/cc-tools v1.0.2 h1:PqQr06BMT/82B7DH5JrHko9C9hejLXHE1rgSpb53Mok= +github.com/hyperledger-labs/cc-tools v1.0.2/go.mod h1:NQyK1wndA/L5EeKqzhLlLGrsfSQJbsvjxbaFiaE6XCI= +github.com/hyperledger/fabric v2.1.1+incompatible h1:cYYRv3vVg4kA6DmrixLxwn1nwBEUuYda8DsMwlaMKbY= +github.com/hyperledger/fabric v2.1.1+incompatible/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0= github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 h1:B1Nt8hKb//KvgGRprk0h1t4lCnwhE9/ryb1WqfZbV+M= github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a h1:HwSCxEeiBthwcazcAykGATQ36oG9M+HEQvGLvB7aLvA= @@ -287,8 +274,6 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= -github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -308,8 +293,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= @@ -347,9 +330,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -418,6 +398,7 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -453,6 +434,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -651,7 +633,6 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -759,7 +740,5 @@ honnef.co/go/tools v0.4.3 h1:o/n5/K5gXqk8Gozvs2cnL0F2S1/g1vcGCAx2vETjITw= honnef.co/go/tools v0.4.3/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/samples/chaincode/confidential-escrow/.env.example b/samples/chaincode/confidential-escrow/.env.example new file mode 100644 index 000000000..75ab220c7 --- /dev/null +++ b/samples/chaincode/confidential-escrow/.env.example @@ -0,0 +1,15 @@ +export CC_ID=confidential-escrow +export CHANNEL_NAME=mychannel +export CORE_PEER_ADDRESS=localhost:7051 +export CORE_PEER_ID=peer0.org1.example.com +export CORE_PEER_ORG_NAME=org1 +export CORE_PEER_LOCALMSPID=Org1MSP +export CORE_PEER_MSPCONFIGPATH=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp +export CORE_PEER_TLS_CERT_FILE=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt +export CORE_PEER_TLS_ENABLED="true" +export CORE_PEER_TLS_KEY_FILE=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key +export CORE_PEER_TLS_ROOTCERT_FILE=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt +export ORDERER_CA=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem +export GATEWAY_CONFIG=$FPC_PATH/samples/deployment/test-network/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/connection-org1.yaml +export FPC_ENABLED=true +export RUN_CCAAS=true diff --git a/samples/chaincode/confidential-escrow/.gitignore b/samples/chaincode/confidential-escrow/.gitignore new file mode 100644 index 000000000..c55c640b7 --- /dev/null +++ b/samples/chaincode/confidential-escrow/.gitignore @@ -0,0 +1,10 @@ +ecc +ecc-bundle +enclave.json +private.pem +public.pem +mrenclave +details.env + +.env +*.bak diff --git a/samples/chaincode/confidential-escrow/Makefile b/samples/chaincode/confidential-escrow/Makefile new file mode 100644 index 000000000..406470419 --- /dev/null +++ b/samples/chaincode/confidential-escrow/Makefile @@ -0,0 +1,7 @@ +TOP = ../../.. +include $(TOP)/ecc_go/build.mk + +CC_NAME ?= confidential-escrow + +EGO_CONFIG_FILE = $(FPC_PATH)/samples/chaincode/confidential-escrow/confidentialEscrowEnclave.json +ECC_MAIN_FILES=$(FPC_PATH)/samples/chaincode/confidential-escrow diff --git a/samples/chaincode/confidential-escrow/README.md b/samples/chaincode/confidential-escrow/README.md new file mode 100644 index 000000000..e53eb644b --- /dev/null +++ b/samples/chaincode/confidential-escrow/README.md @@ -0,0 +1,85 @@ +# Running Procedure + +## Prerequisites + +- FPC is properly set up and built +- `main.sh` script is placed in the chaincode directory +- `.env` file is created with environment variables + +## Setup Files + +**1. Set FPC_PATH:** + +```bash +export FPC_PATH=/project/src/github.com/hyperledger/fabric-private-chaincode +``` + +**2. Create .env file:** + +```bash +touch .env +# Add all environment variables as provided in the .env artifact +cp .env.example .env +``` + +## Running Procedure + +### 1. In 1st terminal window - Setup and Deploy + +```bash +# Get inside dev env +make -C $FPC_PATH/utils/docker run-dev +cd samples/chaincode/confidential-escrow + +# Interactive menu +./main.sh + +## For first time setup (includes ERCC build/Fabric network) +./main.sh full + +## For subsequent runs (skip ERCC build) +./main.sh quick +``` + +### 2. In 2nd terminal window - Docker Environment + +```bash +# Enter docker container +docker exec -it fpc-development-main /bin/bash +cd samples/chaincode/confidential-escrow + +# Interactive menu +./main.sh + +# Setup client environment and initialize enclave +./main.sh docker +``` + +### 3. Run Transactions + +```bash +# Run all basic tests +./main.sh test-all +``` + +## Available Commands + +| Command | Description | +| ---------------------- | ----------------------------------- | +| `./main.sh full` | Complete setup including ERCC build | +| `./main.sh quick` | Quick setup (skip ERCC build) | +| `./main.sh chaincode` | Build chaincode only | +| `./main.sh docker` | Setup docker environment | +| `./main.sh test-basic` | Run basic creation tests | +| `./main.sh test-query` | Run query tests | +| `./main.sh test-all` | Run all tests | +| `./main.sh clean` | Clean and stop network | +| `./main.sh` | Interactive menu | + +## Typical Workflow + +1. **First time:** `./main.sh full` +2. **Enter docker:** `docker exec -it fpc-development-main /bin/bash` +3. **Setup client:** `./main.sh docker` +4. **Run tests:** `./main.sh test-all` +5. **Code changes:** Exit docker → `./main.sh chaincode` → Re-enter docker → Test again diff --git a/samples/chaincode/confidential-escrow/chaincode/assets/digital_asset.go b/samples/chaincode/confidential-escrow/chaincode/assets/digital_asset.go new file mode 100644 index 000000000..ab1177e85 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/assets/digital_asset.go @@ -0,0 +1,57 @@ +package assets + +import ( + "github.com/hyperledger-labs/cc-tools/assets" +) + +var DigitalAssetToken = assets.AssetType{ + Tag: "digitalAsset", + Label: "Digital Asset Token", + Description: "Confidential digital currency token (e.g., CBDC)", + + Props: []assets.AssetProp{ + { + Tag: "name", + Label: "Token Name", + DataType: "string", + Required: true, + }, + { + Tag: "symbol", + Label: "Token Symbol", + DataType: "string", + Required: true, + IsKey: true, + }, + { + Tag: "decimals", + Label: "Decimal Places", + DataType: "number", + Required: true, + }, + { + Tag: "totalSupply", + Label: "Total Supply", + DataType: "number", + Required: true, + }, + { + Tag: "issuerHash", + Label: "Issuer Certificate Hash", + DataType: "string", + Required: true, + }, + { + Tag: "owner", + Label: "Owner Identity", + DataType: "string", + Required: true, + }, + { + Tag: "issuedAt", + Label: "Issued At", + DataType: "datetime", + Required: false, + }, + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/assets/escrow.go b/samples/chaincode/confidential-escrow/chaincode/assets/escrow.go new file mode 100644 index 000000000..6cfb7bd38 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/assets/escrow.go @@ -0,0 +1,69 @@ +package assets + +import ( + "github.com/hyperledger-labs/cc-tools/assets" +) + +var Escrow = assets.AssetType{ + Tag: "escrow", + Label: "Programmable Escrow", + Description: "Confidential escrow contract with programmable conditions", + + Props: []assets.AssetProp{ + { + Tag: "escrowId", + Label: "Escrow ID", + DataType: "string", + Required: true, + IsKey: true, + }, + { + Tag: "buyerPubKey", + Label: "Buyer Public Key", + DataType: "string", + Required: true, + }, + { + Tag: "sellerPubKey", + Label: "Seller Public Key", + DataType: "string", + Required: true, + }, + { + Tag: "amount", + Label: "Escrowed Amount", + DataType: "number", + Required: true, + }, + { + Tag: "assetType", + Label: "Asset Type Reference", + DataType: "->digitalAsset", // References digitalAsset symbol + Required: true, + }, + { + Tag: "conditionValue", + Label: "Condition Value", + DataType: "string", + Required: true, + }, + { + Tag: "status", + Label: "Escrow Status", + DataType: "string", // "Active", "Released", "Refunded" + Required: true, + }, + { + Tag: "createdAt", + Label: "Creation Timestamp", + DataType: "datetime", + Required: false, + }, + { + Tag: "buyerCertHash", + Label: "Buyer Certificate Hash", + DataType: "string", + Required: true, + }, + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/assets/user_directory.go b/samples/chaincode/confidential-escrow/chaincode/assets/user_directory.go new file mode 100644 index 000000000..e70e5dbf0 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/assets/user_directory.go @@ -0,0 +1,33 @@ +package assets + +import ( + "github.com/hyperledger-labs/cc-tools/assets" +) + +var UserDirectory = assets.AssetType{ + Tag: "userdir", + Label: "User Directory", + Description: "Maps user public key hash to wallet ID for authentication", + + Props: []assets.AssetProp{ + { + Tag: "publicKeyHash", + Label: "Public Key Hash", + DataType: "string", + Required: true, + IsKey: true, + }, + { + Tag: "walletId", + Label: "Associated Wallet ID", + DataType: "string", + Required: true, + }, + { + Tag: "certHash", + Label: "Certificate Hash", + DataType: "string", + Required: true, + }, + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/assets/wallet.go b/samples/chaincode/confidential-escrow/chaincode/assets/wallet.go new file mode 100644 index 000000000..acdb877dd --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/assets/wallet.go @@ -0,0 +1,52 @@ +package assets + +import ( + "github.com/hyperledger-labs/cc-tools/assets" +) + +// Wallet represents a confidential user wallet +var Wallet = assets.AssetType{ + Tag: "wallet", + Label: "User Wallet", + Description: "Confidential wallet holding digital assets", + + Props: []assets.AssetProp{ + { + Tag: "walletId", + Label: "Wallet ID", + DataType: "string", + Required: true, + IsKey: true, // primary key + }, + { + Tag: "ownerId", + Label: "Owner Identity", + DataType: "string", + Required: true, + }, + { + Tag: "ownerCertHash", + Label: "Owner Certificate Hash", + DataType: "string", + Required: true, + }, + { + Tag: "balances", + Label: "Token Balance", + DataType: "[]number", + Required: true, + }, + { + Tag: "digitalAssetTypes", + Label: "Asset Type Reference", + DataType: "[]->digitalAsset", // References digitalAsset + Required: true, + }, + { + Tag: "createdAt", + Label: "Creation Timestamp", + DataType: "datetime", + Required: false, + }, + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/escrow.go b/samples/chaincode/confidential-escrow/chaincode/escrow.go new file mode 100644 index 000000000..d7a7e8499 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/escrow.go @@ -0,0 +1,81 @@ +package chaincode + +import ( + "log" + "time" + + "github.com/hyperledger-labs/cc-tools/assets" + tx "github.com/hyperledger-labs/cc-tools/transactions" + + "github.com/hyperledger/fabric-chaincode-go/shim" + pb "github.com/hyperledger/fabric-protos-go/peer" +) + +var startupCheckExecuted = false + +// ConfidentialEscrowCC implements the chaincode interface +type ConfidentialEscrowCC struct{} + +// Init is called during chaincode instantiation +func (t *ConfidentialEscrowCC) Init(stub shim.ChaincodeStubInterface) (response pb.Response) { + log.Println("ConfidentialEscrowCC: Init called") + + res := InitFunc(stub) + startupCheckExecuted = true + if res.Status != 200 { + return res + } + + return shim.Success(nil) +} + +// InitFunc performs startup checks +func InitFunc(stub shim.ChaincodeStubInterface) (response pb.Response) { + defer logTx(stub, time.Now(), &response) + + // Run cc-tools startup checks + err := assets.StartupCheck() + if err != nil { + response = err.GetErrorResponse() + return + } + + err = tx.StartupCheck() + if err != nil { + response = err.GetErrorResponse() + return + } + + log.Println("Confidential Escrow chaincode initialized successfully") + return shim.Success(nil) +} + +// Invoke is called for each transaction +func (t *ConfidentialEscrowCC) Invoke(stub shim.ChaincodeStubInterface) (response pb.Response) { + defer logTx(stub, time.Now(), &response) + + // Ensure startup check is executed + if !startupCheckExecuted { + log.Println("Running startup check...") + res := InitFunc(stub) + if res.Status != 200 { + return res + } + startupCheckExecuted = true + } + + // Use cc-tools transaction runner + result, err := tx.Run(stub) + if err != nil { + response = err.GetErrorResponse() + return + } + + return shim.Success([]byte(result)) +} + +// logTx logs transaction details +func logTx(stub shim.ChaincodeStubInterface, beginTime time.Time, response *pb.Response) { + fn, _ := stub.GetFunctionAndParameters() + log.Printf("%d %s %s %s\n", response.Status, fn, time.Since(beginTime), response.Message) +} diff --git a/samples/chaincode/confidential-escrow/chaincode/header/header.go b/samples/chaincode/confidential-escrow/chaincode/header/header.go new file mode 100644 index 000000000..178f7448b --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/header/header.go @@ -0,0 +1,12 @@ +package header + +var ( + Name = "Confidential Escrow" + Version = "1.0.0" + Colors = map[string][]string{ + "@default": {"#4267B2", "#34495E", "#ECF0F1"}, + } + Title = map[string]string{ + "@default": "Confidential Digital Assets & Programmable Escrow", + } +) diff --git a/samples/chaincode/confidential-escrow/chaincode/server.go b/samples/chaincode/confidential-escrow/chaincode/server.go new file mode 100644 index 000000000..9dbcdd7c0 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/server.go @@ -0,0 +1,46 @@ +package chaincode + +import ( + "os" + + "github.com/hyperledger/fabric-chaincode-go/shim" + fpc "github.com/hyperledger/fabric-private-chaincode/ecc_go/chaincode" +) + +// RunCCaaS starts the chaincode as a service +func RunCCaaS() error { + address := os.Getenv("CHAINCODE_SERVER_ADDRESS") + ccid := os.Getenv("CHAINCODE_PKG_ID") // FPC uses PKG_ID + + var cc shim.Chaincode + if os.Getenv("FPC_ENABLED") == "true" { + cc = fpc.NewPrivateChaincode(new(ConfidentialEscrowCC)) + } else { + cc = new(ConfidentialEscrowCC) + } + + server := &shim.ChaincodeServer{ + CCID: ccid, + Address: address, + CC: cc, + TLSProps: shim.TLSProperties{ + Disabled: true, // TLS handled by FPC + }, + } + + return server.Start() +} + +// StartChaincode starts the chaincode in appropriate mode +func StartChaincode() error { + if os.Getenv("RUN_CCAAS") == "true" { + return RunCCaaS() + } else { + // Fallback for direct start + if os.Getenv("FPC_ENABLED") == "true" { + return shim.Start(fpc.NewPrivateChaincode(new(ConfidentialEscrowCC))) + } else { + return shim.Start(new(ConfidentialEscrowCC)) + } + } +} diff --git a/samples/chaincode/confidential-escrow/chaincode/setup.go b/samples/chaincode/confidential-escrow/chaincode/setup.go new file mode 100644 index 000000000..5556e5d41 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/setup.go @@ -0,0 +1,59 @@ +package chaincode + +import ( + "github.com/hyperledger-labs/cc-tools/assets" + "github.com/hyperledger-labs/cc-tools/events" + tx "github.com/hyperledger-labs/cc-tools/transactions" + + asset "github.com/hyperledger/fabric-private-chaincode/samples/chaincode/confidential-escrow/chaincode/assets" + header "github.com/hyperledger/fabric-private-chaincode/samples/chaincode/confidential-escrow/chaincode/header" + transaction "github.com/hyperledger/fabric-private-chaincode/samples/chaincode/confidential-escrow/chaincode/transactions" +) + +// Transaction and asset lists +var ( + TxList = []tx.Transaction{ + transaction.DebugTest, + // Create + transaction.CreateUserDir, + transaction.CreateWallet, + transaction.CreateDigitalAsset, + transaction.CreateEscrow, + // Read + transaction.ReadUserDir, + transaction.ReadWallet, + transaction.ReadDigitalAsset, + transaction.ReadEscrow, + // misc + transaction.GetBalance, + transaction.GetWalletByOwner, + transaction.MintTokens, + transaction.TransferTokens, + transaction.BurnTokens, + } + AssetTypeList = []assets.AssetType{ + asset.Wallet, + asset.DigitalAssetToken, + asset.UserDirectory, + asset.Escrow, + } + EventTypeList = []events.Event{} // Empty for now +) + +// SetupCC initializes the chaincode with assets and transactions +func SetupCC() error { + // Initialize header info + tx.InitHeader(tx.Header{ + Name: header.Name, + Version: header.Version, + Colors: header.Colors, + Title: header.Title, + }) + + // Initialize transaction and asset lists + tx.InitTxList(TxList) + assets.InitAssetList(AssetTypeList) + events.InitEventList(EventTypeList) + + return nil +} diff --git a/samples/chaincode/confidential-escrow/chaincode/transactions/debug.go b/samples/chaincode/confidential-escrow/chaincode/transactions/debug.go new file mode 100644 index 000000000..95829acde --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/transactions/debug.go @@ -0,0 +1,19 @@ +package transactions + +import ( + "github.com/hyperledger-labs/cc-tools/errors" + sw "github.com/hyperledger-labs/cc-tools/stubwrapper" + "github.com/hyperledger-labs/cc-tools/transactions" +) + +var DebugTest = transactions.Transaction{ + Tag: "debugTest", + Label: "Debug Test", + Description: "Test transaction with no access control", + Method: "GET", + // NO Callers field at all + Args: []transactions.Argument{}, + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + return []byte("Debug test successful"), nil + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/transactions/digitalAsset.go b/samples/chaincode/confidential-escrow/chaincode/transactions/digitalAsset.go new file mode 100644 index 000000000..7aaa1d19b --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/transactions/digitalAsset.go @@ -0,0 +1,686 @@ +package transactions + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/hyperledger-labs/cc-tools/accesscontrol" + "github.com/hyperledger-labs/cc-tools/assets" + "github.com/hyperledger-labs/cc-tools/errors" + "github.com/hyperledger-labs/cc-tools/events" + sw "github.com/hyperledger-labs/cc-tools/stubwrapper" + "github.com/hyperledger-labs/cc-tools/transactions" +) + +var CreateDigitalAsset = transactions.Transaction{ + Tag: "createDigitalAsset", + Label: "Digital Asset Creation", + Description: "Creates a new Digital Asset e.g. CBDC Tokens", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "name", + Label: "Name", + Description: "Name of the Digital Asset", + DataType: "string", + Required: true, + }, + { + Tag: "symbol", + Label: "Symbol", + Description: "Symbol of the Digital Asset", + DataType: "string", + Required: true, + }, + { + Tag: "decimals", + Label: "Decimal Places", + Description: "Decimal Places in Digital Asset", + DataType: "number", + Required: true, + }, + { + Tag: "totalSupply", + Label: "Total Supply", + Description: "Total Supply of the Digital Asset", + DataType: "number", + Required: true, + }, + { + Tag: "owner", + Label: "Owner Identity", + Description: "Identitiy of Digital Asset's creator", + DataType: "string", + Required: true, + }, + { + Tag: "issuedAt", + Label: "Issued At", + Description: "Time at which this token was created", + DataType: "datetime", + Required: false, + }, + { + Tag: "issuerHash", + Label: "Issuer Certificate Hash", + Description: "Hash of Issuer's Certificate who created this Digital Asset", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + name, _ := req["name"].(string) + symbol, _ := req["symbol"].(string) + decimals, _ := req["decimals"].(float64) + totalSupply, _ := req["totalSupply"].(float64) + owner, _ := req["owner"].(string) + issuerHash, _ := req["issuerHash"].(string) + + assetMap := make(map[string]interface{}) + assetMap["@assetType"] = "digitalAsset" + assetMap["name"] = name + assetMap["symbol"] = symbol + assetMap["decimals"] = decimals + assetMap["totalSupply"] = totalSupply + assetMap["owner"] = owner + assetMap["issuedAt"] = time.Now() + assetMap["issuerHash"] = issuerHash + + digitalAsset, err := assets.NewAsset(assetMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to create digital asset") + } + + _, err = digitalAsset.PutNew(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error saving digital asset on blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(digitalAsset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + logMsg, ok := json.Marshal(fmt.Sprintf("New Digital Asset created: %s", name)) + if ok != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + events.CallEvent(stub, "createDigitalAssetLog", logMsg) + + return assetJSON, nil + }, +} + +var ReadDigitalAsset = transactions.Transaction{ + Tag: "readDigitalAsset", + Label: "Read Digital Asset", + Description: "Read a Digital Asset by its symbol", + Method: "GET", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "uuid", + Label: "UUID", + Description: "UUID of the Digital Asset to read", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + uuid, _ := req["uuid"].(string) + key := assets.Key{ + "@key": "digitalAsset:" + uuid, + } + + asset, err := key.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading digital asset from blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(asset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + return assetJSON, nil + }, +} + +var MintTokens = transactions.Transaction{ + Tag: "mintTokens", + Label: "Mint Tokens", + Description: "Mint new tokens to a wallet (issuer only)", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "assetId", + Label: "Asset ID", + Description: "ID of the digital asset", + DataType: "string", + Required: true, + }, + { + Tag: "walletId", + Label: "Target Wallet ID", + Description: "Wallet to mint tokens to", + DataType: "string", + Required: true, + }, + { + Tag: "amount", + Label: "Amount to Mint", + Description: "Number of tokens to mint", + DataType: "number", + Required: true, + }, + { + Tag: "issuerCertHash", + Label: "Issuer Certificate Hash", + Description: "Certificate hash for issuer verification", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + assetId, _ := req["assetId"].(string) + walletId, _ := req["walletId"].(string) + amount, _ := req["amount"].(float64) + issuerCertHash, _ := req["issuerCertHash"].(string) + + // Verify issuer authorization + assetKey := assets.Key{"@key": "digitalAsset:" + assetId} + asset, err := assetKey.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading digital asset", err.Status()) + } + + if asset.GetProp("issuerHash").(string) != issuerCertHash { + return nil, errors.NewCCError("Unauthorized: Only asset issuer can mint tokens", 403) + } + + // Get wallet + walletKey := assets.Key{"@key": "wallet:" + walletId} + walletAsset, err := walletKey.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading wallet", err.Status()) + } + + digitalAssetTypes := walletAsset.GetProp("digitalAssetTypes").([]interface{}) + balances := walletAsset.GetProp("balances").([]interface{}) + + // Find asset index and update balance + assetFound := false + for i, assetRef := range digitalAssetTypes { + var refAssetId string + switch ref := assetRef.(type) { + case map[string]interface{}: + refAssetId = strings.Split(ref["@key"].(string), ":")[1] + case string: + refAssetId = ref + } + + if refAssetId == assetId { + currentBalance := balances[i].(float64) + balances[i] = currentBalance + amount + assetFound = true + break + } + } + + // PPS-fix: if asset not found... then add asset... + if !assetFound { + return nil, errors.NewCCError("Asset not found in wallet", 404) + } + + // Create updated wallet map + walletMap := make(map[string]interface{}) + walletMap["@assetType"] = "wallet" + walletMap["@key"] = "wallet:" + walletId + walletMap["walletId"] = walletAsset.GetProp("walletId") + walletMap["ownerId"] = walletAsset.GetProp("ownerId") + walletMap["ownerCertHash"] = walletAsset.GetProp("ownerCertHash") + walletMap["balances"] = balances + walletMap["digitalAssetTypes"] = digitalAssetTypes + walletMap["createdAt"] = walletAsset.GetProp("createdAt") + + updatedWallet, err := assets.NewAsset(walletMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to update wallet") + } + + _, err = updatedWallet.Put(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error updating wallet", err.Status()) + } + + // Update total supply + currentSupply := asset.GetProp("totalSupply").(float64) + assetMap := make(map[string]interface{}) + assetMap["@assetType"] = "digitalAsset" + assetMap["@key"] = "digitalAsset:" + assetId + assetMap["name"] = asset.GetProp("name") + assetMap["symbol"] = asset.GetProp("symbol") + assetMap["decimals"] = asset.GetProp("decimals") + assetMap["totalSupply"] = currentSupply + amount + assetMap["owner"] = asset.GetProp("owner") + assetMap["issuedAt"] = asset.GetProp("issuedAt") + assetMap["issuerHash"] = asset.GetProp("issuerHash") + + updatedAsset, err := assets.NewAsset(assetMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to update asset") + } + + _, err = updatedAsset.Put(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error updating asset", err.Status()) + } + + response := map[string]interface{}{ + "message": "Tokens minted successfully", + "assetId": assetId, + "walletId": walletId, + "amount": amount, + "totalSupply": currentSupply + amount, + } + + respJSON, jsonErr := json.Marshal(response) + if jsonErr != nil { + return nil, errors.WrapError(nil, "failed to encode response to JSON format") + } + + return respJSON, nil + }, +} + +var TransferTokens = transactions.Transaction{ + Tag: "transferTokens", + Label: "Transfer Tokens", + Description: "Transfer tokens between wallets with balance validation", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "fromWalletId", + Label: "From Wallet ID", + Description: "Source wallet ID", + DataType: "string", + Required: true, + }, + { + Tag: "toWalletId", + Label: "To Wallet ID", + Description: "Destination wallet ID", + DataType: "string", + Required: true, + }, + { + Tag: "assetId", + Label: "Asset ID", + Description: "ID of the digital asset to transfer", + DataType: "string", + Required: true, + }, + { + Tag: "amount", + Label: "Transfer Amount", + Description: "Number of tokens to transfer", + DataType: "number", + Required: true, + }, + { + Tag: "senderCertHash", + Label: "Sender Certificate Hash", + Description: "Certificate hash of the sender for authorization", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + fromWalletId, _ := req["fromWalletId"].(string) + toWalletId, _ := req["toWalletId"].(string) + assetId, _ := req["assetId"].(string) + amount, _ := req["amount"].(float64) + senderCertHash, _ := req["senderCertHash"].(string) + + // Get source wallet + fromKey := assets.Key{"@key": "wallet:" + fromWalletId} + fromWalletAsset, err := fromKey.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading source wallet", err.Status()) + } + + // Verify sender authorization + if fromWalletAsset.GetProp("ownerCertHash").(string) != senderCertHash { + return nil, errors.NewCCError("Unauthorized: Sender certificate mismatch", 403) + } + + // Get destination wallet + toKey := assets.Key{"@key": "wallet:" + toWalletId} + toWalletAsset, err := toKey.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading destination wallet", err.Status()) + } + + // Update source wallet balance + fromAssetTypes := fromWalletAsset.GetProp("digitalAssetTypes").([]interface{}) + fromBalances := fromWalletAsset.GetProp("balances").([]interface{}) + + fromAssetFound := false + for i, assetRef := range fromAssetTypes { + var refAssetId string + switch ref := assetRef.(type) { + case map[string]interface{}: + refAssetId = strings.Split(ref["@key"].(string), ":")[1] + case string: + refAssetId = ref + } + + if refAssetId == assetId { + currentBalance := fromBalances[i].(float64) + if currentBalance < amount { + return nil, errors.NewCCError("Insufficient balance", 400) + } + fromBalances[i] = currentBalance - amount + fromAssetFound = true + break + } + } + + if !fromAssetFound { + return nil, errors.NewCCError("Asset not found in source wallet", 404) + } + + // Update destination wallet balance + toAssetTypes := toWalletAsset.GetProp("digitalAssetTypes").([]interface{}) + toBalances := toWalletAsset.GetProp("balances").([]interface{}) + + toAssetFound := false + for i, assetRef := range toAssetTypes { + var refAssetId string + switch ref := assetRef.(type) { + case map[string]interface{}: + refAssetId = strings.Split(ref["@key"].(string), ":")[1] + case string: + refAssetId = ref + } + + if refAssetId == assetId { + currentBalance := toBalances[i].(float64) + toBalances[i] = currentBalance + amount + toAssetFound = true + break + } + } + + // PPS-fix: if asset not found, Add asset + if !toAssetFound { + return nil, errors.NewCCError("Asset not found in destination wallet", 404) + } + + // Save updated source wallet + fromWalletMap := make(map[string]interface{}) + fromWalletMap["@assetType"] = "wallet" + fromWalletMap["@key"] = "wallet:" + fromWalletId + fromWalletMap["walletId"] = fromWalletAsset.GetProp("walletId") + fromWalletMap["ownerId"] = fromWalletAsset.GetProp("ownerId") + fromWalletMap["ownerCertHash"] = fromWalletAsset.GetProp("ownerCertHash") + fromWalletMap["balances"] = fromBalances + fromWalletMap["digitalAssetTypes"] = fromAssetTypes + fromWalletMap["createdAt"] = fromWalletAsset.GetProp("createdAt") + + updatedFromWallet, err := assets.NewAsset(fromWalletMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to update source wallet") + } + + _, err = updatedFromWallet.Put(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error saving source wallet", err.Status()) + } + + // Save updated destination wallet + toWalletMap := make(map[string]interface{}) + toWalletMap["@assetType"] = "wallet" + toWalletMap["@key"] = "wallet:" + toWalletId + toWalletMap["walletId"] = toWalletAsset.GetProp("walletId") + toWalletMap["ownerId"] = toWalletAsset.GetProp("ownerId") + toWalletMap["ownerCertHash"] = toWalletAsset.GetProp("ownerCertHash") + toWalletMap["balances"] = toBalances + toWalletMap["digitalAssetTypes"] = toAssetTypes + toWalletMap["createdAt"] = toWalletAsset.GetProp("createdAt") + + updatedToWallet, err := assets.NewAsset(toWalletMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to update destination wallet") + } + + _, err = updatedToWallet.Put(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error saving destination wallet", err.Status()) + } + + response := map[string]interface{}{ + "message": "Transfer completed successfully", + "fromWalletId": fromWalletId, + "toWalletId": toWalletId, + "assetId": assetId, + "amount": amount, + } + + respJSON, jsonErr := json.Marshal(response) + if jsonErr != nil { + return nil, errors.WrapError(nil, "failed to encode response to JSON format") + } + + return respJSON, nil + }, +} + +var BurnTokens = transactions.Transaction{ + Tag: "burnTokens", + Label: "Burn Tokens", + Description: "Burn tokens from a wallet (issuer only)", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "assetId", + Label: "Asset ID", + Description: "ID of the digital asset", + DataType: "string", + Required: true, + }, + { + Tag: "walletId", + Label: "Wallet ID", + Description: "Wallet to burn tokens from", + DataType: "string", + Required: true, + }, + { + Tag: "amount", + Label: "Amount to Burn", + Description: "Number of tokens to burn", + DataType: "number", + Required: true, + }, + { + Tag: "issuerCertHash", + Label: "Issuer Certificate Hash", + Description: "Certificate hash for issuer verification", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + assetId, _ := req["assetId"].(string) + walletId, _ := req["walletId"].(string) + amount, _ := req["amount"].(float64) + issuerCertHash, _ := req["issuerCertHash"].(string) + + // Verify issuer authorization + assetKey := assets.Key{"@key": "digitalAsset:" + assetId} + asset, err := assetKey.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading digital asset", err.Status()) + } + + if asset.GetProp("issuerHash").(string) != issuerCertHash { + return nil, errors.NewCCError("Unauthorized: Only asset issuer can burn tokens", 403) + } + + // Get wallet + walletKey := assets.Key{"@key": "wallet:" + walletId} + walletAsset, err := walletKey.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading wallet", err.Status()) + } + + digitalAssetTypes := walletAsset.GetProp("digitalAssetTypes").([]interface{}) + balances := walletAsset.GetProp("balances").([]interface{}) + + // Find asset index and update balance + assetFound := false + for i, assetRef := range digitalAssetTypes { + var refAssetId string + switch ref := assetRef.(type) { + case map[string]interface{}: + refAssetId = strings.Split(ref["@key"].(string), ":")[1] + case string: + refAssetId = ref + } + + if refAssetId == assetId { + currentBalance := balances[i].(float64) + if currentBalance < amount { + return nil, errors.NewCCError("Insufficient balance to burn", 400) + } + balances[i] = currentBalance - amount + assetFound = true + break + } + } + + if !assetFound { + return nil, errors.NewCCError("Asset not found in wallet", 404) + } + + // Create updated wallet map + walletMap := make(map[string]interface{}) + walletMap["@assetType"] = "wallet" + walletMap["@key"] = "wallet:" + walletId + walletMap["walletId"] = walletAsset.GetProp("walletId") + walletMap["ownerId"] = walletAsset.GetProp("ownerId") + walletMap["ownerCertHash"] = walletAsset.GetProp("ownerCertHash") + walletMap["balances"] = balances + walletMap["digitalAssetTypes"] = digitalAssetTypes + walletMap["createdAt"] = walletAsset.GetProp("createdAt") + + updatedWallet, err := assets.NewAsset(walletMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to update wallet") + } + + _, err = updatedWallet.Put(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error updating wallet", err.Status()) + } + + // Update total supply + currentSupply := asset.GetProp("totalSupply").(float64) + assetMap := make(map[string]interface{}) + assetMap["@assetType"] = "digitalAsset" + assetMap["@key"] = "digitalAsset:" + assetId + assetMap["name"] = asset.GetProp("name") + assetMap["symbol"] = asset.GetProp("symbol") + assetMap["decimals"] = asset.GetProp("decimals") + assetMap["totalSupply"] = currentSupply - amount + assetMap["owner"] = asset.GetProp("owner") + assetMap["issuedAt"] = asset.GetProp("issuedAt") + assetMap["issuerHash"] = asset.GetProp("issuerHash") + + updatedAsset, err := assets.NewAsset(assetMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to update asset") + } + + _, err = updatedAsset.Put(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error updating asset", err.Status()) + } + + response := map[string]interface{}{ + "message": "Tokens burned successfully", + "assetId": assetId, + "walletId": walletId, + "amount": amount, + "totalSupply": currentSupply - amount, + } + + respJSON, jsonErr := json.Marshal(response) + if jsonErr != nil { + return nil, errors.WrapError(nil, "failed to encode response to JSON format") + } + + return respJSON, nil + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/transactions/escrow.go b/samples/chaincode/confidential-escrow/chaincode/transactions/escrow.go new file mode 100644 index 000000000..b13640953 --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/transactions/escrow.go @@ -0,0 +1,174 @@ +package transactions + +import ( + "encoding/json" + "time" + + "github.com/hyperledger-labs/cc-tools/accesscontrol" + "github.com/hyperledger-labs/cc-tools/assets" + "github.com/hyperledger-labs/cc-tools/errors" + sw "github.com/hyperledger-labs/cc-tools/stubwrapper" + "github.com/hyperledger-labs/cc-tools/transactions" +) + +var CreateEscrow = transactions.Transaction{ + Tag: "createEscrow", + Label: "Escrow Creation", + Description: "Creates a new escrow", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "escrowId", + Label: "Escrow ID", + Description: "ID of Escrow", + DataType: "string", + Required: true, + }, + { + Tag: "buyerPubKey", + Label: "Buyer Public Key", + DataType: "string", + Required: true, + }, + { + Tag: "sellerPubKey", + Label: "Seller Public Key", + DataType: "string", + Required: true, + }, + { + Tag: "amount", + Label: "Escrowed Amount", + DataType: "number", + Required: true, + }, + { + Tag: "assetType", + Label: "Asset Type Reference", + DataType: "->digitalAsset", + Required: true, + }, + { + Tag: "conditionValue", + Label: "Condition Value", + DataType: "string", + Required: true, + }, + { + Tag: "status", + Label: "Escrow Status", + DataType: "string", + Required: true, + }, + { + Tag: "createdAt", + Label: "Creation Timestamp", + DataType: "datetime", + Required: false, + }, + { + Tag: "buyerCertHash", + Label: "Buyer Certificate Hash", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + escrowId, _ := req["escrowId"].(string) + buyerPubKey, _ := req["buyerPubKey"].(string) + sellerPubKey, _ := req["sellerPubKey"].(string) + amount, _ := req["amount"].(float64) + assetType, _ := req["assetType"].(interface{}) + conditionValue, _ := req["conditionValue"].(string) + status, _ := req["status"].(string) + buyerCertHash, _ := req["buyerCertHash"].(string) + + escrowMap := make(map[string]interface{}) + escrowMap["@assetType"] = "escrow" + escrowMap["escrowId"] = escrowId + escrowMap["buyerPubKey"] = buyerPubKey + escrowMap["sellerPubKey"] = sellerPubKey + escrowMap["amount"] = amount + escrowMap["assetType"] = assetType + escrowMap["conditionValue"] = conditionValue + escrowMap["status"] = status + escrowMap["createdAt"] = time.Now() + escrowMap["buyerCertHash"] = buyerCertHash + + escrowAsset, err := assets.NewAsset(escrowMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to create escrow asset") + } + + _, err = escrowAsset.PutNew(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error saving escrow on blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(escrowAsset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode escrow to JSON format") + } + + return assetJSON, nil + }, +} + +var ReadEscrow = transactions.Transaction{ + Tag: "readEscrow", + Label: "Read Escrow", + Description: "Read an Escrow by its escrowId", + Method: "GET", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "uuid", + Label: "UUID", + Description: "UUID of the Digital Asset to read", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + uuid, _ := req["uuid"].(string) + + key := assets.Key{ + "@key": "escrow:" + uuid, + } + + asset, err := key.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading escrow from blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(asset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode escrow to JSON format") + } + + return assetJSON, nil + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/transactions/user_directory.go b/samples/chaincode/confidential-escrow/chaincode/transactions/user_directory.go new file mode 100644 index 000000000..a397706ef --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/transactions/user_directory.go @@ -0,0 +1,132 @@ +package transactions + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger-labs/cc-tools/accesscontrol" + "github.com/hyperledger-labs/cc-tools/assets" + "github.com/hyperledger-labs/cc-tools/errors" + "github.com/hyperledger-labs/cc-tools/events" + sw "github.com/hyperledger-labs/cc-tools/stubwrapper" + "github.com/hyperledger-labs/cc-tools/transactions" +) + +var CreateUserDir = transactions.Transaction{ + Tag: "createUserDir", + Label: "User Directory Creation", + Description: "Creates a new User entry", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "publicKeyHash", + Label: "Public Key Hash", + DataType: "string", + Required: true, + }, + { + Tag: "walletId", + Label: "Associated Wallet ID", + DataType: "string", + Required: true, + }, + { + Tag: "certHash", + Label: "Certificate Hash", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + publicKeyHash, _ := req["publicKeyHash"].(string) + walletId, _ := req["walletId"].(string) + certHash, _ := req["certHash"].(string) + + userDirMap := make(map[string]interface{}) + userDirMap["@assetType"] = "userdir" + userDirMap["publicKeyHash"] = publicKeyHash + userDirMap["walletId"] = walletId + userDirMap["certHash"] = certHash + + userDirAsset, err := assets.NewAsset(userDirMap) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading user directory entry from blockchain", err.Status()) + } + + _, err = userDirAsset.PutNew(stub) + if err != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + assetJson, nerr := json.Marshal(userDirAsset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + logMsg, ok := json.Marshal(fmt.Sprintf("New user directory created: %s", publicKeyHash)) + if ok != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + events.CallEvent(stub, "createUserDirLog", logMsg) + + return assetJson, nil + }, +} + +var ReadUserDir = transactions.Transaction{ + Tag: "readUserDir", + Label: "Read User Directory", + Description: "Read a User Directory by its publicKeyHash", + Method: "GET", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "uuid", + Label: "UUID", + Description: "UUID of the Digital Asset to read", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + uuid, _ := req["uuid"].(string) + + key := assets.Key{ + "@key": "userdir:" + uuid, + } + + asset, err := key.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error user directory entry from blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(asset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode asset to JSON format") + } + + return assetJSON, nil + }, +} diff --git a/samples/chaincode/confidential-escrow/chaincode/transactions/wallet.go b/samples/chaincode/confidential-escrow/chaincode/transactions/wallet.go new file mode 100644 index 000000000..4438250fa --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/transactions/wallet.go @@ -0,0 +1,347 @@ +package transactions + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/hyperledger-labs/cc-tools/accesscontrol" + "github.com/hyperledger-labs/cc-tools/assets" + "github.com/hyperledger-labs/cc-tools/errors" + sw "github.com/hyperledger-labs/cc-tools/stubwrapper" + "github.com/hyperledger-labs/cc-tools/transactions" +) + +var CreateWallet = transactions.Transaction{ + Tag: "createWallet", + Label: "Wallet Creation", + Description: "Creates a new Wallet", + Method: "POST", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "walletId", + Label: "Wallet ID", + Description: "ID of Wallet", + DataType: "string", + Required: true, + }, + { + Tag: "ownerId", + Label: "Owner Identity", + DataType: "string", + Required: true, + }, + { + Tag: "ownerCertHash", + Label: "Owner Certificate Hash", + Description: "Hash of Owner's Certificate who created this wallet", + DataType: "string", + Required: true, // testing purpose + }, + { + Tag: "balances", + Label: "Different Token Balance", + DataType: "[]number", + Required: true, + }, + { + Tag: "digitalAssetTypes", + Label: "Digital Assets in Holding", + DataType: "[]->digitalAsset", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + walletId, _ := req["walletId"].(string) + ownerId, _ := req["ownerId"].(string) + ownerCertHash, _ := req["ownerCertHash"].(string) + balances, _ := req["balances"].([]interface{}) + assetTypes, _ := req["digitalAssetTypes"].([]interface{}) + + fmt.Printf("DEBUG: Received assetTypes: %+v\n", assetTypes) + fmt.Printf("DEBUG: Type of first element: %T\n", assetTypes[0]) + + var processedAssetTypes []interface{} + for _, assetType := range assetTypes { + switch v := assetType.(type) { + case string: + // If it's a string (UUID), convert to proper reference format + processedAssetTypes = append(processedAssetTypes, map[string]interface{}{ + "@key": "digitalAsset:" + v, + }) + case map[string]interface{}: + // If it's already a map (proper reference), use as-is + processedAssetTypes = append(processedAssetTypes, v) + default: + processedAssetTypes = append(processedAssetTypes, v) + } + } + + walletMap := make(map[string]interface{}) + walletMap["@assetType"] = "wallet" + walletMap["walletId"] = walletId + walletMap["ownerId"] = ownerId + walletMap["ownerCertHash"] = ownerCertHash + walletMap["balances"] = balances + walletMap["digitalAssetTypes"] = processedAssetTypes + walletMap["createdAt"] = time.Now() + + walletAsset, err := assets.NewAsset(walletMap) + if err != nil { + return nil, errors.WrapError(err, "Failed to create wallet asset") + } + + _, err = walletAsset.PutNew(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error saving wallet on blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(walletAsset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode wallet to JSON format") + } + + return assetJSON, nil + }, +} + +var GetBalance = transactions.Transaction{ + Tag: "getBalance", + Label: "Get Wallet Balance", + Description: "Get balance of a specific token in wallet with authentication", + Method: "GET", + // Do we need this? + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "walletId", + Label: "Wallet ID", + Description: "ID of the wallet", + DataType: "string", + Required: true, + }, + { + Tag: "assetSymbol", + Label: "Asset Symbol", + Description: "Symbol of the digital asset to check balance for", + DataType: "string", + Required: true, + }, + { + Tag: "ownerCertHash", + Label: "Owner Certificate Hash", + Description: "Certificate hash for ownership verification", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + walletId, _ := req["walletId"].(string) + assetSymbol, _ := req["assetSymbol"].(string) + ownerCertHash, _ := req["ownerCertHash"].(string) + + // Get wallet + key := assets.Key{ + "@key": "wallet:" + walletId, + } + + walletAsset, err := key.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading wallet from blockchain", err.Status()) + } + + // Verify ownership + if walletAsset.GetProp("ownerCertHash").(string) != ownerCertHash { + return nil, errors.NewCCError("Unauthorized: Certificate hash mismatch", 403) + } + + // Find asset index + digitalAssetTypes := walletAsset.GetProp("digitalAssetTypes").([]interface{}) + balances := walletAsset.GetProp("balances").([]interface{}) + + for i, assetRef := range digitalAssetTypes { + // Get the referenced asset + var assetKey string + switch ref := assetRef.(type) { + case map[string]interface{}: + assetKey = ref["@key"].(string) + case string: + assetKey = "digitalAsset:" + ref + } + + // Read the asset to get its symbol + refKey := assets.Key{"@key": assetKey} + asset, assetErr := refKey.Get(stub) + if assetErr != nil { + continue + } + + if asset.GetProp("symbol").(string) == assetSymbol { + balance := balances[i].(float64) + response := map[string]interface{}{ + "walletId": walletId, + "assetSymbol": assetSymbol, + "balance": balance, + } + responseJSON, jsonErr := json.Marshal(response) + if jsonErr != nil { + return nil, errors.WrapError(nil, "failed to encode response to JSON format") + } + return responseJSON, nil + } + } + + return nil, errors.NewCCError("Asset not found in wallet", 404) + }, +} + +var GetWalletByOwner = transactions.Transaction{ + Tag: "getWalletByOwner", + Label: "Get Wallet By Owner", + Description: "Find wallet by owner identity", + Method: "GET", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, + { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "ownerId", + Label: "Owner Identity", + Description: "Identity of the wallet owner", + DataType: "string", + Required: true, + }, + { + Tag: "ownerCertHash", + Label: "Owner Certificate Hash", + Description: "Certificate hash for authentication", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + ownerId, _ := req["ownerId"].(string) + ownerCertHash, _ := req["ownerCertHash"].(string) + + // Search for wallet by owner + query := map[string]interface{}{ + "selector": map[string]interface{}{ + "@assetType": "wallet", + "ownerId": ownerId, + "ownerCertHash": ownerCertHash, + }, + } + + searchResponse, err := assets.Search(stub, query, "", true) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error searching for wallet", 500) + } + + if len(searchResponse.Result) == 0 { + return nil, errors.NewCCError("Wallet not found for owner", 404) + } + + responseJSON, jsonErr := json.Marshal(searchResponse) + if jsonErr != nil { + return nil, errors.WrapErrorWithStatus(nil, "Error marshaling response", 500) + } + + return responseJSON, nil + }, +} + +// Need to impose restriction +var ReadWallet = transactions.Transaction{ + Tag: "readWallet", + Label: "Read Wallet", + Description: "Read a Wallet by its walletId", + Method: "GET", + Callers: []accesscontrol.Caller{ + { + MSP: "Org1MSP", + OU: "admin", + }, { + MSP: "Org2MSP", + OU: "admin", + }, + }, + + Args: []transactions.Argument{ + { + Tag: "uuid", + Label: "UUID", + Description: "UUID of the Digital Asset to read", + DataType: "string", + Required: true, + }, + }, + + Routine: func(stub *sw.StubWrapper, req map[string]interface{}) ([]byte, errors.ICCError) { + uuid, _ := req["uuid"].(string) + + key := assets.Key{ + "@key": "wallet:" + uuid, + } + + asset, err := key.Get(stub) + if err != nil { + return nil, errors.WrapErrorWithStatus(err, "Error reading wallet from blockchain", err.Status()) + } + + assetJSON, nerr := json.Marshal(asset) + if nerr != nil { + return nil, errors.WrapError(nil, "failed to encode wallet to JSON format") + } + + return assetJSON, nil + }, +} + +/* +1. Use hash(txnId) => UUID +2. get it from `stub` + +--- + +Split txnID pool among user + -> Modulo ops + +-> Better random num gen + -> sha256(__) + +--- + +use txnID as UUID of the assets + -> For multiple asset generated in 1 txn => Deal with it using counter or something +*/ diff --git a/samples/chaincode/confidential-escrow/chaincode/utils.go b/samples/chaincode/confidential-escrow/chaincode/utils.go new file mode 100644 index 000000000..4b1cfd4ef --- /dev/null +++ b/samples/chaincode/confidential-escrow/chaincode/utils.go @@ -0,0 +1,14 @@ +package chaincode + +import ( + "fmt" + "os" +) + +// GenerateCollection handles collection generation (if needed) +func GenerateCollection(orgs []string) { + fmt.Println("Collection generation called with orgs:", orgs) + fmt.Println("Collection generation not implemented yet") + // Exit after generating (like in cc-tools-demo) + os.Exit(0) +} diff --git a/samples/chaincode/confidential-escrow/confidential-escrow-compose.yaml b/samples/chaincode/confidential-escrow/confidential-escrow-compose.yaml new file mode 100644 index 000000000..e1904ab4c --- /dev/null +++ b/samples/chaincode/confidential-escrow/confidential-escrow-compose.yaml @@ -0,0 +1,12 @@ +services: + # org1 + ecc.peer0.org1.example.com: + environment: + - RUN_CCAAS=true + - FPC_ENABLED=true + + # org2 + ecc.peer0.org2.example.com: + environment: + - RUN_CCAAS=true + - FPC_ENABLED=true diff --git a/samples/chaincode/confidential-escrow/confidentialEscrowEnclave.json b/samples/chaincode/confidential-escrow/confidentialEscrowEnclave.json new file mode 100644 index 000000000..1ca911b98 --- /dev/null +++ b/samples/chaincode/confidential-escrow/confidentialEscrowEnclave.json @@ -0,0 +1,32 @@ +{ + "exe": "ecc", + "key": "private.pem", + "debug": true, + "heapSize": 512, + "productID": 1, + "securityVersion": 1, + "mounts": null, + "files": null, + "env": [ + { + "name": "CHAINCODE_SERVER_ADDRESS", + "fromHost": true + }, + { + "name": "CHAINCODE_PKG_ID", + "fromHost": true + }, + { + "name": "FPC_ENABLED", + "fromHost": true + }, + { + "name": "RUN_CCAAS", + "fromHost": true + }, + { + "name": "FABRIC_LOGGING_SPEC", + "fromHost": true + } + ] +} diff --git a/samples/chaincode/confidential-escrow/go.mod b/samples/chaincode/confidential-escrow/go.mod new file mode 100644 index 000000000..e64228a2d --- /dev/null +++ b/samples/chaincode/confidential-escrow/go.mod @@ -0,0 +1,35 @@ +module github.com/hyperledger/fabric-private-chaincode/samples/chaincode/confidential-escrow + +go 1.24.2 + +require ( + github.com/hyperledger-labs/cc-tools v1.0.2 + github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a + github.com/hyperledger/fabric-private-chaincode v0.0.0-00010101000000-000000000000 + github.com/hyperledger/fabric-protos-go v0.3.0 +) + +require ( + github.com/Shopify/sarama v0.0.0-00010101000000-000000000000 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/hyperledger/fabric v2.1.1+incompatible // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/stretchr/testify v1.10.0 // indirect + github.com/sykesm/zap-logfmt v0.0.4 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect +) + +replace github.com/hyperledger/fabric-private-chaincode => ../../../ + +replace github.com/Shopify/sarama => github.com/IBM/sarama v1.45.2 diff --git a/samples/chaincode/confidential-escrow/go.sum b/samples/chaincode/confidential-escrow/go.sum new file mode 100644 index 000000000..7f6192a75 --- /dev/null +++ b/samples/chaincode/confidential-escrow/go.sum @@ -0,0 +1,164 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/IBM/sarama v1.45.2 h1:8m8LcMCu3REcwpa7fCP6v2fuPuzVwXDAM2DOv3CBrKw= +github.com/IBM/sarama v1.45.2/go.mod h1:ppaoTcVdGv186/z6MEKsMm70A5fwJfRTpstI37kVn3Y= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= +github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hyperledger-labs/cc-tools v1.0.2 h1:PqQr06BMT/82B7DH5JrHko9C9hejLXHE1rgSpb53Mok= +github.com/hyperledger-labs/cc-tools v1.0.2/go.mod h1:NQyK1wndA/L5EeKqzhLlLGrsfSQJbsvjxbaFiaE6XCI= +github.com/hyperledger/fabric v2.1.1+incompatible h1:cYYRv3vVg4kA6DmrixLxwn1nwBEUuYda8DsMwlaMKbY= +github.com/hyperledger/fabric v2.1.1+incompatible/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0= +github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 h1:B1Nt8hKb//KvgGRprk0h1t4lCnwhE9/ryb1WqfZbV+M= +github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a h1:HwSCxEeiBthwcazcAykGATQ36oG9M+HEQvGLvB7aLvA= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a/go.mod h1:TDSu9gxURldEnaGSFbH1eMlfSQBWQcMQfnDBcpQv5lU= +github.com/hyperledger/fabric-protos-go v0.3.0 h1:MXxy44WTMENOh5TI8+PCK2x6pMj47Go2vFRKDHB2PZs= +github.com/hyperledger/fabric-protos-go v0.3.0/go.mod h1:WWnyWP40P2roPmmvxsUXSvVI/CF6vwY1K1UFidnKBys= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= +github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/samples/chaincode/confidential-escrow/main.go b/samples/chaincode/confidential-escrow/main.go new file mode 100644 index 000000000..53d8c640d --- /dev/null +++ b/samples/chaincode/confidential-escrow/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "flag" + "log" + + cc "github.com/hyperledger/fabric-private-chaincode/samples/chaincode/confidential-escrow/chaincode" +) + +func main() { + // Handle collection generation flag + genFlag := flag.Bool("g", false, "Enable collection generation") + flag.Bool("orgs", false, "List of orgs to generate collection for") + flag.Parse() + if *genFlag { + listOrgs := flag.Args() + cc.GenerateCollection(listOrgs) + return + } + + log.Printf("Starting Confidential Escrow Chaincode v1.0.0") + + // Setup CC-Tools components + err := cc.SetupCC() + if err != nil { + log.Printf("Error setting up chaincode: %s", err) + return + } + + // Start chaincode + err = cc.StartChaincode() + if err != nil { + log.Printf("Error starting chaincode: %s", err) + } +} diff --git a/samples/chaincode/confidential-escrow/main.sh b/samples/chaincode/confidential-escrow/main.sh new file mode 100755 index 000000000..a043c697b --- /dev/null +++ b/samples/chaincode/confidential-escrow/main.sh @@ -0,0 +1,384 @@ +#!/bin/bash + +# Combined FPC Setup and Test Script +# Description: One script to rule them all + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Logging functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if FPC_PATH is set +check_fpc_path() { + if [ -z "$FPC_PATH" ]; then + log_error "FPC_PATH is not set. Please export FPC_PATH=/path/to/your/fpc" + exit 1 + fi + log_info "Using FPC_PATH: $FPC_PATH" +} + +# Source environment variables +source_env() { + # Get the directory where the script is located + SCRIPT_DIR="$FPC_PATH/samples/chaincode/confidential-escrow/" + + if [ -f "$SCRIPT_DIR/.env" ]; then + source "$SCRIPT_DIR/.env" + log_info "Environment variables loaded from .env" + else + log_error ".env file not found. Make sure it exists in script directory: $SCRIPT_DIR" + exit 1 + fi +} + +# Function to run commands with error handling +run_cmd() { + local cmd="$1" + local desc="$2" + + log_info "$desc" + echo "Running: $cmd" + + if eval "$cmd"; then + log_success "$desc - COMPLETED" + else + log_error "$desc - FAILED" + exit 1 + fi +} + +# Build ERCC (one time requirement) +build_ercc() { + log_info "=== BUILDING ERCC ===" + run_cmd "GOOS=linux make -C $FPC_PATH/ercc build docker" "Building ERCC" +} + +# Build chaincode +build_chaincode() { + log_info "=== BUILDING CHAINCODE ===" + run_cmd "GOOS=linux make -C $FPC_PATH/samples/chaincode/confidential-escrow with_go docker" "Building chaincode" +} + +# One-time setup (run only once) +initial_setup() { + log_info "=== INITIAL SETUP (One-time only) ===" + cd $FPC_PATH/samples/deployment/test-network + run_cmd "./setup.sh" "Running initial setup" +} + +# Setup test network +setup_network() { + log_info "=== SETTING UP NETWORK ===" + cd $FPC_PATH/samples/deployment/test-network/fabric-samples/test-network + + run_cmd "./network.sh down" "Bringing down network" + run_cmd "./network.sh up -ca" "Starting network" + run_cmd "./network.sh createChannel -c mychannel" "Creating channel" +} + +# Install FPC +install_fpc() { + log_info "=== INSTALLING FPC ===" + export CC_ID=confidential-escrow + export CC_PATH="$FPC_PATH/samples/chaincode/confidential-escrow/" + export CC_VER=$(cat "$FPC_PATH/samples/chaincode/confidential-escrow/mrenclave") + + cd $FPC_PATH/samples/deployment/test-network + run_cmd "./installFPC.sh" "Installing FPC" +} + +# Start ERCC-ECC +start_ercc() { + log_info "=== STARTING ERCC-ECC ===" + export EXTRA_COMPOSE_FILE="$FPC_PATH/samples/chaincode/confidential-escrow/confidential-escrow-compose.yaml" + cd $FPC_PATH/samples/deployment/test-network + run_cmd "make ercc-ecc-start" "Starting ERCC-ECC" +} + +# Setup docker environment +setup_docker() { + log_info "=== SETTING UP DOCKER ENVIRONMENT ===" + source_env + + cd $FPC_PATH/samples/deployment/test-network + run_cmd "./update-connection.sh" "Updating connections" + run_cmd "./update-external-connection.sh" "Updating external connections" + + cd $FPC_PATH/samples/application/simple-cli-go + run_cmd "./fpcclient init $CORE_PEER_ID" "Initializing enclave" + log_success "Docker environment ready!" +} + +# Test functions +test_schema() { + log_info "Getting schema..." + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient invoke getSchema +} + +test_debug() { + log_info "Running debug test..." + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient invoke debugTest '{}' +} + +WALLET_UUID="" +ESCROW_UUID="" +DIGITAL_ASSET_UUID="" +DIGITAL_ASSET_JSON="" + +store_asset_data() { + local output="$1" + DIGITAL_ASSET_JSON=$(echo "$output" | grep '^>' | sed 's/^> //') + DIGITAL_ASSET_UUID=$(echo "$DIGITAL_ASSET_JSON" | grep -o '"@key":"digitalAsset:[^"]*"' | cut -d':' -f3 | tr -d '"') +} + +store_wallet_data() { + local output="$1" + WALLET_UUID=$(echo "$output" | grep '^>' | sed 's/^> //' | grep -o '"@key":"wallet:[^"]*"' | cut -d':' -f3 | tr -d '"') +} + +store_escrow_data() { + local output="$1" + ESCROW_UUID=$(echo "$output" | grep '^>' | sed 's/^> //' | grep -o '"@key":"escrow:[^"]*"' | cut -d':' -f3 | tr -d '"') +} + +test_create_asset() { + log_info "Creating digital asset..." + cd $FPC_PATH/samples/application/simple-cli-go + local output=$(./fpcclient invoke createDigitalAsset '{ + "name": "CBDCC", + "symbol": "CBDCC", + "decimals": 2, + "totalSupply": 1000000, + "owner": "central_bank", + "issuerHash": "sha256:abc123" + }' 2>&1) + echo "$output" + store_asset_data "$output" +} + +test_create_wallet() { + log_info "Creating wallet..." + cd $FPC_PATH/samples/application/simple-cli-go + local output=$(./fpcclient invoke createWallet "{ + \"walletId\": \"wallet-111\", + \"ownerId\": \"Abhinav\", + \"ownerCertHash\": \"sha256:def456\", + \"balances\": [0], + \"digitalAssetTypes\": [$DIGITAL_ASSET_JSON] + }" 2>&1) + echo "$output" + store_wallet_data "$output" +} + +test_create_wallet2() { + log_info "Creating second wallet..." + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient invoke createWallet "{ + \"walletId\": \"wallet-222\", + \"ownerId\": \"Bob\", + \"ownerCertHash\": \"sha256:ghi789\", + \"balances\": [0], + \"digitalAssetTypes\": [$DIGITAL_ASSET_JSON] + }" +} + +test_create_escrow() { + log_info "Creating escrow..." + cd $FPC_PATH/samples/application/simple-cli-go + local output=$(./fpcclient invoke createEscrow "{ + \"escrowId\": \"escrow-111\", + \"buyerPubKey\": \"buyer_pub\", + \"sellerPubKey\": \"seller_pub\", + \"amount\": 1000, + \"assetType\": $DIGITAL_ASSET_JSON, + \"conditionValue\": \"sha256:secret123\", + \"status\": \"Active\", + \"buyerCertHash\": \"sha256:buyer_cert\" + }" 2>&1) + echo "$output" + store_escrow_data "$output" +} + +test_query_asset() { + log_info "Querying digital asset..." + cd $FPC_PATH/samples/application/simple-cli-go + log_info $DIGITAL_ASSET_UUID + log_info $DIGITAL_ASSET_JSON + ./fpcclient query readDigitalAsset "{\"uuid\": \"$DIGITAL_ASSET_UUID\"}" +} + +test_query_wallet() { + log_info "Querying wallet..." + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient query readWallet "{\"uuid\": \"$WALLET_UUID\"}" +} + +test_get_balance() { + log_info "Testing getBalance transaction" + + # Test getting balance for CBDCC in wallet1 + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient query getBalance '{ + "walletId": "wallet-111", + "assetSymbol": "CBDCC", + "ownerCertHash": "sha256:def456" + }' +} + +test_get_wallet_by_owner() { + log_info "Testing getWalletByOwner transaction" + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient query getWalletByOwner '{ + "ownerId": "Abhinav", + "ownerCertHash": "sha256:def456" + }' +} + +test_mint_tokens() { + log_info "Testing mintTokens transaction" + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient invoke mintTokens "{ + \"assetId\": \"$DIGITAL_ASSET_UUID\", + \"walletId\": \"wallet-111\", + \"amount\": 100, + \"issuerCertHash\": \"sha256:abc123\" + }" +} + +test_transfer_tokens() { + log_info "Testing transferTokens transaction" + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient invoke transferTokens "{ + \"fromWalletId\": \"wallet-111\", + \"toWalletId\": \"wallet-222\", + \"assetId\": \"$DIGITAL_ASSET_UUID\", + \"amount\": 50, + \"senderCertHash\": \"sha256:def456\" + }" +} + +test_burn_tokens() { + log_info "Testing burnTokens transaction" + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient invoke burnTokens "{ + \"assetId\": \"$DIGITAL_ASSET_UUID\", + \"walletId\": \"wallet-111\", + \"amount\": 25, + \"issuerCertHash\": \"sha256:abc123\" + }" +} + +test_query_escrow() { + log_info "Querying escrow..." + cd $FPC_PATH/samples/application/simple-cli-go + ./fpcclient query readEscrow "{\"uuid\": \"$ESCROW_UUID\"}" +} + +# Batch operations +run_tests() { + log_info "=== RUNNING TESTS ===" + source_env + test_schema + test_debug + test_create_asset + test_create_wallet + test_create_wallet2 + test_create_escrow + test_query_asset + test_query_wallet + test_query_escrow + test_get_balance + test_get_wallet_by_owner + test_mint_tokens + test_get_balance + test_transfer_tokens + test_get_balance + test_burn_tokens + test_get_balance + log_success "=== TESTS COMPLETED ===" +} + +# Main menu +show_menu() { + echo + echo "=== FPC CONTROL SCRIPT ===" + echo "SETUP OPTIONS:" + echo "1. Full Setup (ERCC + Network + Install)" + echo "2. Quick Setup (Skip ERCC build)" + echo "3. Setup Docker Environment" + echo + echo "TEST OPTIONS:" + echo "4. Run All Tests" + echo + echo "0. Exit" + echo +} + +# Main execution +main() { + check_fpc_path + + case "${1:-menu}" in + "full") + build_ercc + build_chaincode + initial_setup + setup_network + install_fpc + start_ercc + ;; + "quick") + build_chaincode + setup_network + install_fpc + start_ercc + ;; + "docker") + setup_docker + ;; + "test-all") + run_tests + ;; + "menu") + while true; do + show_menu + read -p "Choose an option (0-8): " choice + case $choice in + 1) main "full" ;; + 2) main "quick" ;; + 3) main "docker" ;; + 4) main "test-all" ;; + 0) exit 0 ;; + *) log_error "Invalid option" ;; + esac + echo + read -p "Press Enter to continue..." + done + ;; + *) + echo "Usage: $0 [full|quick|chaincode|docker|clean|test-basic|test-query|test-all|menu]" + exit 1 + ;; + esac +} + +main "$@"